mirror of https://github.com/QingdaoU/Spirit.git
Feature/upload files optional (#196)
* comment.forms pass tmp file to magic * core.tags settings * make comment upload image/file optional * gitignore update * delete manage * gitignore update * delete manage * generic editor upload * editor pass image extensions * fix coffee tests * bookmark coffee lil refactor * update js deps * rename test * comment.forms change file name format from hash.file.ext -> file_hash.ext * add @rkenmi to authors * update history
This commit is contained in:
parent
ca4b5e047f
commit
c2f9ed3a49
|
@ -1,8 +1,10 @@
|
|||
# Spirit
|
||||
spirit/search/whoosh_index/
|
||||
db.sqlite3
|
||||
example/media/
|
||||
example/static/
|
||||
/spirit/search/whoosh_index/
|
||||
/db.sqlite3
|
||||
/example/media/
|
||||
/example/static/
|
||||
/manage.py
|
||||
/project
|
||||
|
||||
# Node
|
||||
node_modules
|
||||
|
|
|
@ -10,3 +10,4 @@ various contributors:
|
|||
* Robert Kolner @RobertKolner <robert.kolner@gmail.com>
|
||||
* Benjamin Murden @benmurden <benmurden@github.com>
|
||||
* Li Dashuang @lidashuang <ldshuang@gmail.com>
|
||||
* Rick Miyamoto @rkenmi
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
* Drops support for Python 3.3
|
||||
* Adds support for Django 1.9 and 1.10
|
||||
* Adds python-magic dependency (to check uploaded files)
|
||||
* New: file upload on comments
|
||||
* Improvement: Adds `ST_UPLOAD_IMAGE_ENABLED`
|
||||
to enable/disable image uploads and `ST_UPLOAD_FILE_ENABLED`
|
||||
to enable/disable file uploads
|
||||
* Remove deprecated `topic_poll` app
|
||||
* Remove deprecated (since v0.2) `spirit_user.User` (PR #141),
|
||||
read the wiki or the PR for a workaround
|
||||
|
|
|
@ -49,7 +49,7 @@ gulp.task('coffee', function() {
|
|||
pathVendors + '**/*.coffee',
|
||||
pathCoffee + 'util.coffee',
|
||||
pathCoffee + 'tab.coffee',
|
||||
pathCoffee + 'editor_image_upload.coffee',
|
||||
pathCoffee + 'editor_file_upload.coffee',
|
||||
pathCoffee + '*.coffee'
|
||||
])
|
||||
.pipe(sourcemaps.init())
|
||||
|
|
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
|
@ -11,11 +11,17 @@
|
|||
"gulp-sourcemaps": "^1.6.0",
|
||||
"gulp-uglify": "^1.4.2",
|
||||
"gulp-util": "^3.0.6",
|
||||
"karma": "^0.13.10",
|
||||
"karma-cli": "^0.1.1",
|
||||
"karma-jasmine": "^0.2.2"
|
||||
"jasmine-core": "^2.8.0",
|
||||
"karma": "^1.7.1",
|
||||
"karma-cli": "^1.0.1",
|
||||
"karma-jasmine": "^1.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"gulp": "gulp"
|
||||
}
|
||||
},
|
||||
"name": "Spirit",
|
||||
"version": "1.0.0",
|
||||
"repository": "https://github.com/nitely/Spirit.git",
|
||||
"author": "nitely <ecastroborsani@gmail.com>",
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
import magic
|
||||
import logging
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.files.storage import default_storage
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.encoding import smart_bytes
|
||||
from django.core.files.uploadedfile import TemporaryUploadedFile
|
||||
|
||||
from ..core import utils
|
||||
from ..core.utils.markdown import Markdown
|
||||
|
@ -20,6 +22,7 @@ from .models import Comment
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CommentForm(forms.ModelForm):
|
||||
comment = forms.CharField(
|
||||
max_length=settings.ST_COMMENT_MAX_LEN,
|
||||
|
@ -153,35 +156,41 @@ class CommentFileForm(forms.Form):
|
|||
|
||||
def clean_file(self):
|
||||
file = self.cleaned_data['file']
|
||||
|
||||
try:
|
||||
file_mime = magic.from_buffer(file.read(131072), mime=True)
|
||||
if isinstance(file, TemporaryUploadedFile):
|
||||
file_mime = magic.from_file(file.temporary_file_path(), mime=True)
|
||||
else: # In-memory file
|
||||
file_mime = magic.from_buffer(file.read(), mime=True)
|
||||
except magic.MagicException as e:
|
||||
logger.exception(e)
|
||||
raise forms.ValidationError(_("The file could not be validated"))
|
||||
else:
|
||||
# Won't ever raise. Has at most one '.' so lstrip is fine here
|
||||
ext = os.path.splitext(file.name)[1].lstrip('.')
|
||||
|
||||
mime = settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.get(ext, None)
|
||||
if mime is None:
|
||||
raise forms.ValidationError(
|
||||
_("Unsupported file extension %s. Supported extensions are %s."
|
||||
% (ext, ", ".join(settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.keys()))
|
||||
)
|
||||
)
|
||||
if mime != file_mime:
|
||||
raise forms.ValidationError(
|
||||
_("Unsupported file mime type %s. Supported types are %s."
|
||||
% (file_mime, ", ".join(settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.values()))
|
||||
)
|
||||
)
|
||||
# Won't ever raise. Has at most one '.' so lstrip is fine here
|
||||
ext = os.path.splitext(file.name)[1].lstrip('.')
|
||||
mime = settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.get(ext, None)
|
||||
|
||||
return file
|
||||
if mime is None:
|
||||
raise forms.ValidationError(
|
||||
_("Unsupported file extension %s. Supported extensions are %s." % (
|
||||
ext,
|
||||
", ".join(
|
||||
sorted(settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.keys())))))
|
||||
|
||||
if mime != file_mime:
|
||||
raise forms.ValidationError(
|
||||
_("Unsupported file mime type %s. Supported types are %s." % (
|
||||
file_mime,
|
||||
", ".join(
|
||||
sorted(settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.values())))))
|
||||
|
||||
return file
|
||||
|
||||
def save(self):
|
||||
file = self.cleaned_data['file']
|
||||
file_hash = utils.get_file_hash(file)
|
||||
file.name = ''.join((file_hash, '.', file.name.lower()))
|
||||
file_name, file_ext = os.path.splitext(file.name.lower())
|
||||
file.name = ''.join((file_name, '_', file_hash, file_ext))
|
||||
name = os.path.join('spirit', 'files', str(self.user.pk), file.name)
|
||||
name = default_storage.save(name, file)
|
||||
file.url = default_storage.url(name)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.html import mark_safe
|
||||
from django.conf import settings
|
||||
|
||||
|
@ -24,23 +24,29 @@ def render_comments_form(topic, next=None):
|
|||
|
||||
@register.simple_tag()
|
||||
def get_allowed_file_types():
|
||||
return ".{}".format(", .".join(settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.keys()))
|
||||
return ", ".join(
|
||||
'.%s' % ext
|
||||
for ext in sorted(settings.ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE.keys()))
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def get_allowed_image_types():
|
||||
return ", ".join(
|
||||
'.%s' % ext
|
||||
for ext in sorted(settings.ST_ALLOWED_UPLOAD_IMAGE_FORMAT))
|
||||
|
||||
|
||||
ACTIONS = {
|
||||
MOVED: _("This topic has been moved"),
|
||||
CLOSED: _("This topic has been closed"),
|
||||
UNCLOSED: _("This topic has been unclosed"),
|
||||
PINNED: _("This topic has been pinned"),
|
||||
UNPINNED: _("This topic has been unpinned")}
|
||||
|
||||
|
||||
@register.simple_tag()
|
||||
def get_comment_action_text(action):
|
||||
if action == MOVED:
|
||||
return _("This topic has been moved")
|
||||
elif action == CLOSED:
|
||||
return _("This topic has been closed")
|
||||
elif action == UNCLOSED:
|
||||
return _("This topic has been unclosed")
|
||||
elif action == PINNED:
|
||||
return _("This topic has been pinned")
|
||||
elif action == UNPINNED:
|
||||
return _("This topic has been unpinned")
|
||||
else:
|
||||
return _("Unknown topic moderation action")
|
||||
return ACTIONS.get(action, _("Unknown topic moderation action"))
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{% load spirit_tags i18n %}
|
||||
{% load static from staticfiles %}
|
||||
|
||||
{% load_settings 'ST_UPLOAD_IMAGE_ENABLED' 'ST_UPLOAD_FILE_ENABLED' %}
|
||||
|
||||
<div class="comment-text js-box-preview-content" style="display:none;"></div>
|
||||
<ul class="reply-markdown">
|
||||
<li><a class="js-box-bold" href="#" title="{% trans "Bold" %}"><i class="fa fa-bold"></i></a></li><!--
|
||||
|
@ -8,7 +10,9 @@
|
|||
--><li><a class="js-box-list" href="#" title="{% trans "List" %}"><i class="fa fa-list"></i></a></li><!--
|
||||
--><li><a class="js-box-url" href="#" title="{% trans "URL" %}"><i class="fa fa-link"></i></a></li><!--
|
||||
--><li><a class="js-box-image" href="#" title="{% trans "Image" %}"><i class="fa fa-picture-o"></i></a></li><!--
|
||||
--><li><a class="js-box-file" href="#" title="{% trans "File" %}"><i class="fa fa-file"></i></a></li><!--
|
||||
-->{% if st_settings.ST_UPLOAD_FILE_ENABLED %}<li>
|
||||
<a class="js-box-file" href="#" title="{% trans "File" %}"><i class="fa fa-file"></i></a>
|
||||
</li>{% endif %}<!--
|
||||
--><li><a class="js-box-poll" href="#" title="{% trans "Poll" %}"><i class="fa fa-bar-chart-o"></i></a></li><!--
|
||||
--><li><a class="js-box-preview" href="#" title="{% trans "Preview" %}"><i class="fa fa-eye"></i></a></li>
|
||||
</ul>
|
||||
|
@ -28,17 +32,22 @@
|
|||
} );
|
||||
|
||||
$( '.js-reply' ).find( 'textarea' )
|
||||
.editor_image_upload( {
|
||||
csrfToken: "{{ csrf_token }}",
|
||||
target: "{% url "spirit:comment:image-upload-ajax" %}",
|
||||
placeholderText: "{% trans "uploading {image_name}" %}"
|
||||
} )
|
||||
.editor_file_upload({
|
||||
csrfToken: "{{ csrf_token }}",
|
||||
target: "{% url "spirit:comment:file-upload-ajax" %}",
|
||||
placeholderText: "{% trans "uploading {file_name}" %}",
|
||||
allowedFileMedia: "{% get_allowed_file_types %}"
|
||||
} )
|
||||
{% if st_settings.ST_UPLOAD_IMAGE_ENABLED %}
|
||||
.editor_image_upload( {
|
||||
csrfToken: "{{ csrf_token }}",
|
||||
target: "{% url "spirit:comment:image-upload-ajax" %}",
|
||||
placeholderText: "{% trans "uploading {name}" %}",
|
||||
allowedFileMedia: "{% get_allowed_image_types %}"
|
||||
} )
|
||||
{% endif %}
|
||||
{% if st_settings.ST_UPLOAD_FILE_ENABLED %}
|
||||
.editor_file_upload({
|
||||
csrfToken: "{{ csrf_token }}",
|
||||
target: "{% url "spirit:comment:file-upload-ajax" %}",
|
||||
placeholderText: "{% trans "uploading {name}" %}",
|
||||
allowedFileMedia: "{% get_allowed_file_types %}"
|
||||
} )
|
||||
{% endif %}
|
||||
.editor( {
|
||||
boldedText: "{% trans "bolded text" %}",
|
||||
italicisedText: "{% trans "italicised text" %}",
|
||||
|
|
|
@ -456,30 +456,70 @@ class CommentViewTest(TestCase):
|
|||
self.assertIn('error', res.keys())
|
||||
self.assertIn('image', res['error'].keys())
|
||||
|
||||
@override_settings(MEDIA_ROOT=os.path.join(settings.BASE_DIR, 'media_test'))
|
||||
@override_settings(
|
||||
MEDIA_ROOT=os.path.join(settings.BASE_DIR, 'media_test'),
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE=2621440)
|
||||
def test_comment_file_upload(self):
|
||||
"""
|
||||
comment file upload
|
||||
Check (in-memory) upload files are checked
|
||||
"""
|
||||
utils.login(self)
|
||||
|
||||
# sample valid pdf - https://stackoverflow.com/a/17280876
|
||||
file = BytesIO(b'%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1'
|
||||
b'>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n000000'
|
||||
b'0010 00000 n\n0000000053 00000 n\n0000000102 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxre'
|
||||
b'f\n149\n%EOF\n')
|
||||
file = BytesIO(
|
||||
b'%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1'
|
||||
b'>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n000000'
|
||||
b'0010 00000 n\n0000000053 00000 n\n0000000102 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxre'
|
||||
b'f\n149\n%EOF\n')
|
||||
files = {'file': SimpleUploadedFile('file.pdf', file.read(), content_type='application/pdf'), }
|
||||
response = self.client.post(reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
response = self.client.post(
|
||||
reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
|
||||
res = json.loads(response.content.decode('utf-8'))
|
||||
file_url = os.path.join(
|
||||
settings.MEDIA_URL, 'spirit', 'files', str(self.user.pk), "fadcb2389bb2b69b46bc54185de0ae91.file.pdf"
|
||||
settings.MEDIA_URL, 'spirit', 'files', str(self.user.pk), "file_fadcb2389bb2b69b46bc54185de0ae91.pdf"
|
||||
).replace("\\", "/")
|
||||
self.assertEqual(res['url'], file_url)
|
||||
file_path = os.path.join(
|
||||
settings.MEDIA_ROOT, 'spirit', 'files', str(self.user.pk), "fadcb2389bb2b69b46bc54185de0ae91.file.pdf"
|
||||
settings.MEDIA_ROOT, 'spirit', 'files', str(self.user.pk), "file_fadcb2389bb2b69b46bc54185de0ae91.pdf"
|
||||
)
|
||||
|
||||
with open(file_path, 'rb') as fh:
|
||||
file.seek(0)
|
||||
self.assertEqual(fh.read(), file.read())
|
||||
|
||||
shutil.rmtree(settings.MEDIA_ROOT) # cleanup
|
||||
|
||||
@override_settings(
|
||||
MEDIA_ROOT=os.path.join(settings.BASE_DIR, 'media_test'),
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE=1)
|
||||
def test_comment_file_upload_tmp_file(self):
|
||||
"""
|
||||
Check (tmp) upload files are checked
|
||||
"""
|
||||
utils.login(self)
|
||||
file = BytesIO(
|
||||
b'%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1'
|
||||
b'>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n000000'
|
||||
b'0010 00000 n\n0000000053 00000 n\n0000000102 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxre'
|
||||
b'f\n149\n%EOF\n')
|
||||
files = {
|
||||
'file': SimpleUploadedFile(
|
||||
'file_large.pdf', file.read(), content_type='application/pdf'),}
|
||||
response = self.client.post(
|
||||
reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
|
||||
res = json.loads(response.content.decode('utf-8'))
|
||||
file_url = os.path.join(
|
||||
settings.MEDIA_URL, 'spirit', 'files', str(self.user.pk), "file_large_fadcb2389bb2b69b46bc54185de0ae91.pdf"
|
||||
).replace("\\", "/")
|
||||
self.assertEqual(res['url'], file_url)
|
||||
file_path = os.path.join(
|
||||
settings.MEDIA_ROOT, 'spirit', 'files', str(self.user.pk), "file_large_fadcb2389bb2b69b46bc54185de0ae91.pdf"
|
||||
)
|
||||
|
||||
with open(file_path, 'rb') as fh:
|
||||
|
@ -494,19 +534,22 @@ class CommentViewTest(TestCase):
|
|||
"""
|
||||
utils.login(self)
|
||||
# sample valid pdf - https://stackoverflow.com/a/17280876
|
||||
file = BytesIO(b'%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1'
|
||||
b'>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n000000'
|
||||
b'0010 00000 n\n0000000053 00000 n\n0000000102 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxre'
|
||||
b'f\n149\n%EOF\n')
|
||||
file = BytesIO(
|
||||
b'%PDF-1.0\n1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1'
|
||||
b'>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj\nxref\n0 4\n0000000000 65535 f\n000000'
|
||||
b'0010 00000 n\n0000000053 00000 n\n0000000102 00000 n\ntrailer<</Size 4/Root 1 0 R>>\nstartxre'
|
||||
b'f\n149\n%EOF\n')
|
||||
files = {'file': SimpleUploadedFile('fake.gif', file.read(), content_type='application/pdf'), }
|
||||
response = self.client.post(reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
response = self.client.post(
|
||||
reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
res = json.loads(response.content.decode('utf-8'))
|
||||
self.assertIn('error', res.keys())
|
||||
self.assertIn('file', res['error'].keys())
|
||||
self.assertEqual(res['error']['file'],
|
||||
['Unsupported file extension gif. Supported extensions are doc, docx, pdf.'])
|
||||
self.assertIn('error', res)
|
||||
self.assertIn('file', res['error'])
|
||||
self.assertEqual(
|
||||
res['error']['file'],
|
||||
['Unsupported file extension gif. Supported extensions are doc, docx, pdf.'])
|
||||
|
||||
def test_comment_file_upload_invalid_mime(self):
|
||||
"""
|
||||
|
@ -514,19 +557,22 @@ class CommentViewTest(TestCase):
|
|||
"""
|
||||
utils.login(self)
|
||||
file = BytesIO(b'BAD\x02D\x01\x00;')
|
||||
files = {'file': SimpleUploadedFile('file.pdf', file.read(), content_type='application/pdf'), }
|
||||
response = self.client.post(reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
files = {
|
||||
'file': SimpleUploadedFile(
|
||||
'file.pdf', file.read(), content_type='application/pdf')}
|
||||
response = self.client.post(
|
||||
reverse('spirit:comment:file-upload-ajax'),
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
data=files)
|
||||
res = json.loads(response.content.decode('utf-8'))
|
||||
self.assertIn('error', res.keys())
|
||||
self.assertIn('file', res['error'].keys())
|
||||
self.assertEqual(res['error']['file'],
|
||||
[
|
||||
'Unsupported file mime type application/octet-stream. '
|
||||
'Supported types are application/msword, '
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document, '
|
||||
'application/pdf.'])
|
||||
self.assertIn('error', res)
|
||||
self.assertIn('file', res['error'])
|
||||
self.assertEqual(
|
||||
res['error']['file'],
|
||||
['Unsupported file mime type application/octet-stream. '
|
||||
'Supported types are application/msword, '
|
||||
'application/pdf, '
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document.'])
|
||||
|
||||
|
||||
class CommentModelsTest(TestCase):
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url, include
|
||||
from django.conf import settings
|
||||
|
||||
import spirit.comment.bookmark.urls
|
||||
import spirit.comment.flag.urls
|
||||
|
@ -23,12 +24,17 @@ urlpatterns = [
|
|||
url(r'^(?P<pk>\d+)/delete/$', views.delete, name='delete'),
|
||||
url(r'^(?P<pk>\d+)/undelete/$', views.delete, kwargs={'remove': False, }, name='undelete'),
|
||||
|
||||
url(r'^upload/$', views.image_upload_ajax, name='image-upload-ajax'),
|
||||
url(r'^upload/file/$', views.file_upload_ajax, name='file-upload-ajax'),
|
||||
|
||||
url(r'^bookmark/', include(spirit.comment.bookmark.urls, namespace='bookmark')),
|
||||
url(r'^flag/', include(spirit.comment.flag.urls, namespace='flag')),
|
||||
url(r'^history/', include(spirit.comment.history.urls, namespace='history')),
|
||||
url(r'^like/', include(spirit.comment.like.urls, namespace='like')),
|
||||
url(r'^poll/', include(spirit.comment.poll.urls, namespace='poll')),
|
||||
]
|
||||
|
||||
if settings.ST_UPLOAD_IMAGE_ENABLED:
|
||||
urlpatterns.append(
|
||||
url(r'^upload/$', views.image_upload_ajax, name='image-upload-ajax'))
|
||||
|
||||
if settings.ST_UPLOAD_FILE_ENABLED:
|
||||
urlpatterns.append(
|
||||
url(r'^upload/file/$', views.file_upload_ajax, name='file-upload-ajax'))
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -63,17 +63,16 @@
|
|||
};
|
||||
|
||||
Bookmark.prototype.sendCommentNumber = function() {
|
||||
var post, sentCommentNumber;
|
||||
var sentCommentNumber;
|
||||
if (this.mark.isSending) {
|
||||
return;
|
||||
}
|
||||
this.mark.isSending = true;
|
||||
sentCommentNumber = this.mark.commentNumber;
|
||||
post = $.post(this.options.target, {
|
||||
return $.post(this.options.target, {
|
||||
csrfmiddlewaretoken: this.options.csrfToken,
|
||||
comment_number: this.mark.commentNumber
|
||||
});
|
||||
return post.always((function(_this) {
|
||||
}).always((function(_this) {
|
||||
return function() {
|
||||
_this.mark.isSending = false;
|
||||
if (_this.mark.commentNumber > sentCommentNumber) {
|
||||
|
|
|
@ -5,150 +5,176 @@
|
|||
*/
|
||||
|
||||
(function() {
|
||||
var $, EditorImageUpload,
|
||||
var $, EditorUpload,
|
||||
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
||||
|
||||
$ = jQuery;
|
||||
|
||||
EditorImageUpload = (function() {
|
||||
EditorImageUpload.prototype.defaults = {
|
||||
EditorUpload = (function() {
|
||||
EditorUpload.prototype.defaults = {
|
||||
csrfToken: "csrf_token",
|
||||
target: "target url",
|
||||
placeholderText: "uploading {image_name}"
|
||||
placeholderText: "uploading {name}",
|
||||
allowedFileMedia: ["*/*"]
|
||||
};
|
||||
|
||||
function EditorImageUpload(el, options) {
|
||||
EditorUpload.prototype._meta = {
|
||||
fieldName: "file",
|
||||
tag: "[{text}]({url})",
|
||||
elm: ".js-box-file"
|
||||
};
|
||||
|
||||
function EditorUpload(el, options, meta) {
|
||||
if (meta == null) {
|
||||
meta = null;
|
||||
}
|
||||
this.openFileDialog = bind(this.openFileDialog, this);
|
||||
this.textReplace = bind(this.textReplace, this);
|
||||
this.addStatusError = bind(this.addStatusError, this);
|
||||
this.addError = bind(this.addError, this);
|
||||
this.addImage = bind(this.addImage, this);
|
||||
this.addFile = bind(this.addFile, this);
|
||||
this.buildFormData = bind(this.buildFormData, this);
|
||||
this.addPlaceholder = bind(this.addPlaceholder, this);
|
||||
this.sendFile = bind(this.sendFile, this);
|
||||
this.el = $(el);
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.meta = $.extend({}, this._meta, meta || {});
|
||||
this.formFile = $("<form/>");
|
||||
this.inputFile = $("<input/>", {
|
||||
type: "file",
|
||||
accept: "image/*"
|
||||
accept: this.options.allowedFileMedia
|
||||
}).appendTo(this.formFile);
|
||||
this.setUp();
|
||||
}
|
||||
|
||||
EditorImageUpload.prototype.setUp = function() {
|
||||
var $boxImage;
|
||||
EditorUpload.prototype.setUp = function() {
|
||||
var $boxElm;
|
||||
if (window.FormData == null) {
|
||||
return;
|
||||
}
|
||||
this.inputFile.on('change', this.sendFile);
|
||||
$boxImage = $(".js-box-image");
|
||||
$boxImage.on('click', this.openFileDialog);
|
||||
return $boxImage.on('click', this.stopClick);
|
||||
$boxElm = $(this.meta.elm);
|
||||
$boxElm.on('click', this.openFileDialog);
|
||||
return $boxElm.on('click', this.stopClick);
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.sendFile = function() {
|
||||
var file, formData, placeholder, post;
|
||||
EditorUpload.prototype.sendFile = function() {
|
||||
var file, formData, placeholder;
|
||||
file = this.inputFile.get(0).files[0];
|
||||
placeholder = this.addPlaceholder(file);
|
||||
formData = this.buildFormData(file);
|
||||
post = $.ajax({
|
||||
$.ajax({
|
||||
url: this.options.target,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST'
|
||||
});
|
||||
post.done((function(_this) {
|
||||
}).done((function(_this) {
|
||||
return function(data) {
|
||||
if ("url" in data) {
|
||||
return _this.addImage(data, file, placeholder);
|
||||
return _this.addFile(data, file, placeholder);
|
||||
} else {
|
||||
return _this.addError(data, placeholder);
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
post.fail((function(_this) {
|
||||
})(this)).fail((function(_this) {
|
||||
return function(jqxhr, textStatus, error) {
|
||||
return _this.addStatusError(textStatus, error, placeholder);
|
||||
};
|
||||
})(this));
|
||||
post.always((function(_this) {
|
||||
})(this)).always((function(_this) {
|
||||
return function() {
|
||||
return _this.formFile.get(0).reset();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.addPlaceholder = function(file) {
|
||||
EditorUpload.prototype.addPlaceholder = function(file) {
|
||||
var placeholder;
|
||||
placeholder = $.format("![" + this.options.placeholderText + "]()", {
|
||||
image_name: file.name
|
||||
placeholder = $.format(this.meta.tag, {
|
||||
text: $.format(this.options.placeholderText, {
|
||||
name: file.name
|
||||
}),
|
||||
url: ""
|
||||
});
|
||||
this.el.val(this.el.val() + placeholder);
|
||||
return placeholder;
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.buildFormData = function(file) {
|
||||
EditorUpload.prototype.buildFormData = function(file) {
|
||||
var formData;
|
||||
formData = new FormData();
|
||||
formData.append('csrfmiddlewaretoken', this.options.csrfToken);
|
||||
formData.append('image', file);
|
||||
formData.append(this.meta.fieldName, file);
|
||||
return formData;
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.addImage = function(data, file, placeholder) {
|
||||
EditorUpload.prototype.addFile = function(data, file, placeholder) {
|
||||
var imageTag;
|
||||
imageTag = $.format("![{name}]({url})", {
|
||||
name: file.name,
|
||||
imageTag = $.format(this.meta.tag, {
|
||||
text: file.name,
|
||||
url: data.url
|
||||
});
|
||||
return this.textReplace(placeholder, imageTag);
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.addError = function(data, placeholder) {
|
||||
EditorUpload.prototype.addError = function(data, placeholder) {
|
||||
var error;
|
||||
error = JSON.stringify(data);
|
||||
return this.textReplace(placeholder, "![" + error + "]()");
|
||||
return this.textReplace(placeholder, $.format(this.meta.tag, {
|
||||
text: error,
|
||||
url: ""
|
||||
}));
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.addStatusError = function(textStatus, error, placeholder) {
|
||||
EditorUpload.prototype.addStatusError = function(textStatus, error, placeholder) {
|
||||
var errorTag;
|
||||
errorTag = $.format("![error: {code} {error}]()", {
|
||||
code: textStatus,
|
||||
error: error
|
||||
errorTag = $.format(this.meta.tag, {
|
||||
text: $.format("error: {code} {error}", {
|
||||
code: textStatus,
|
||||
error: error
|
||||
}),
|
||||
url: ""
|
||||
});
|
||||
return this.textReplace(placeholder, errorTag);
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.textReplace = function(find, replace) {
|
||||
EditorUpload.prototype.textReplace = function(find, replace) {
|
||||
this.el.val(this.el.val().replace(find, replace));
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.openFileDialog = function() {
|
||||
EditorUpload.prototype.openFileDialog = function() {
|
||||
this.inputFile.trigger('click');
|
||||
};
|
||||
|
||||
EditorImageUpload.prototype.stopClick = function(e) {
|
||||
EditorUpload.prototype.stopClick = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
};
|
||||
|
||||
return EditorImageUpload;
|
||||
return EditorUpload;
|
||||
|
||||
})();
|
||||
|
||||
$.fn.extend({
|
||||
editor_file_upload: function(options) {
|
||||
return this.each(function() {
|
||||
if (!$(this).data('plugin_editor_file_upload')) {
|
||||
return $(this).data('plugin_editor_file_upload', new EditorUpload(this, options));
|
||||
}
|
||||
});
|
||||
},
|
||||
editor_image_upload: function(options) {
|
||||
return this.each(function() {
|
||||
if (!$(this).data('plugin_editor_image_upload')) {
|
||||
return $(this).data('plugin_editor_image_upload', new EditorImageUpload(this, options));
|
||||
return $(this).data('plugin_editor_image_upload', new EditorUpload(this, options, {
|
||||
fieldName: "image",
|
||||
tag: "![{text}]({url})",
|
||||
elm: ".js-box-image"
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.fn.editor_image_upload.EditorImageUpload = EditorImageUpload;
|
||||
|
||||
}).call(this);
|
|
@ -35,7 +35,7 @@
|
|||
};
|
||||
|
||||
Storage.prototype.updateStorage = function() {
|
||||
var err, error, value;
|
||||
var err, value;
|
||||
value = this.el.val();
|
||||
try {
|
||||
localStorage[this.lsKey] = value;
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
## Installation (Ubuntu 14.04)
|
||||
## Installation (Ubuntu 16.04)
|
||||
|
||||
### Install Node.js
|
||||
|
||||
Install io.js
|
||||
```
|
||||
$ curl -sL https://deb.nodesource.com/setup_iojs_3.x | sudo -E bash -
|
||||
$ sudo apt-get install -y iojs
|
||||
$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
|
||||
$ sudo apt-get install -y nodejs
|
||||
```
|
||||
|
||||
Install dependencies
|
||||
> If you are a node.js user then install nvm to manage the versions
|
||||
|
||||
### Install yarn (js package manager)
|
||||
|
||||
```
|
||||
$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
|
||||
$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||
$ sudo apt-get update && sudo apt-get install yarn
|
||||
```
|
||||
|
||||
> On Ubuntu 17 you may want to remove `cmdtest` if you get any error `sudo apt remove cmdtest`
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```
|
||||
$ cd ./Spirit
|
||||
$ npm install -y .
|
||||
$ yarn
|
||||
```
|
||||
|
||||
## Build
|
||||
|
|
|
@ -57,15 +57,14 @@ class Bookmark
|
|||
@mark.isSending = true
|
||||
sentCommentNumber = @mark.commentNumber
|
||||
|
||||
post = $.post(
|
||||
$.post(
|
||||
@options.target,
|
||||
{
|
||||
csrfmiddlewaretoken: @options.csrfToken,
|
||||
comment_number: @mark.commentNumber
|
||||
}
|
||||
)
|
||||
|
||||
post.always( =>
|
||||
.always( =>
|
||||
@mark.isSending = false
|
||||
|
||||
if @mark.commentNumber > sentCommentNumber
|
||||
|
|
|
@ -16,8 +16,6 @@ class Editor
|
|||
linkUrlText: "link url",
|
||||
imageText: "image text",
|
||||
imageUrlText: "image url",
|
||||
fileText: "file text",
|
||||
fileUrlText: "file url",
|
||||
pollTitleText: "Title",
|
||||
pollChoiceText: "Description"
|
||||
}
|
||||
|
@ -37,7 +35,6 @@ class Editor
|
|||
$('.js-box-list').on('click', @addList)
|
||||
$('.js-box-url').on('click', @addUrl)
|
||||
$('.js-box-image').on('click', @addImage)
|
||||
$('.js-box-file').on('click', @addFile)
|
||||
$('.js-box-poll').on('click', @addPoll)
|
||||
$('.js-box-preview').on('click', @togglePreview)
|
||||
|
||||
|
@ -77,10 +74,6 @@ class Editor
|
|||
@wrapSelection("![", "](#{ @options.imageUrlText })", @options.imageText)
|
||||
return false
|
||||
|
||||
addFile: =>
|
||||
@wrapSelection("[", "](#{ @options.fileUrlText })", @options.fileText)
|
||||
return false
|
||||
|
||||
addPoll: =>
|
||||
poll = "\n\n[poll name=#{@pollCounter}]\n" +
|
||||
"# #{@options.pollTitleText}\n" +
|
||||
|
|
|
@ -6,18 +6,24 @@
|
|||
$ = jQuery
|
||||
|
||||
|
||||
class EditorFileUpload
|
||||
class EditorUpload
|
||||
|
||||
defaults: {
|
||||
csrfToken: "csrf_token",
|
||||
target: "target url",
|
||||
placeholderText: "uploading {file_name}",
|
||||
allowedFileMedia: [".doc", ".docx", ".pdf"]
|
||||
placeholderText: "uploading {name}",
|
||||
allowedFileMedia: ["*/*"]
|
||||
}
|
||||
_meta: {
|
||||
fieldName: "file",
|
||||
tag: "[{text}]({url})",
|
||||
elm: ".js-box-file"
|
||||
}
|
||||
|
||||
constructor: (el, options) ->
|
||||
@el = $(el)
|
||||
constructor: (el, options, meta=null) ->
|
||||
@el = $(el) # Editor box
|
||||
@options = $.extend({}, @defaults, options)
|
||||
@meta = $.extend({}, @_meta, meta or {})
|
||||
@formFile = $("<form/>")
|
||||
@inputFile = $("<input/>", {
|
||||
type: "file",
|
||||
|
@ -33,35 +39,32 @@ class EditorFileUpload
|
|||
# TODO: fixme, having multiple editors
|
||||
# in the same page would open several
|
||||
# dialogs on box-image click
|
||||
$boxImage = $(".js-box-file")
|
||||
$boxImage.on('click', @openFileDialog)
|
||||
$boxImage.on('click', @stopClick)
|
||||
$boxElm = $(@meta.elm)
|
||||
$boxElm.on('click', @openFileDialog)
|
||||
$boxElm.on('click', @stopClick)
|
||||
|
||||
sendFile: =>
|
||||
file = @inputFile.get(0).files[0]
|
||||
placeholder = @addPlaceholder(file)
|
||||
formData = @buildFormData(file)
|
||||
|
||||
post = $.ajax({
|
||||
$.ajax({
|
||||
url: @options.target,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST'
|
||||
})
|
||||
|
||||
post.done((data) =>
|
||||
.done((data) =>
|
||||
if "url" of data
|
||||
@addFile(data, file, placeholder)
|
||||
else
|
||||
@addError(data, placeholder)
|
||||
)
|
||||
|
||||
post.fail((jqxhr, textStatus, error) =>
|
||||
.fail((jqxhr, textStatus, error) =>
|
||||
@addStatusError(textStatus, error, placeholder)
|
||||
)
|
||||
|
||||
post.always(() =>
|
||||
.always(() =>
|
||||
# Reset the input after uploading,
|
||||
# fixes uploading the same image twice
|
||||
@formFile.get(0).reset()
|
||||
|
@ -70,27 +73,34 @@ class EditorFileUpload
|
|||
return
|
||||
|
||||
addPlaceholder: (file) =>
|
||||
placeholder = $.format("[#{ @options.placeholderText }]()", {file_name: file.name, })
|
||||
placeholder = $.format(@meta.tag, {
|
||||
text: $.format(@options.placeholderText, {name: file.name}),
|
||||
url: ""})
|
||||
@el.val(@el.val() + placeholder)
|
||||
return placeholder
|
||||
|
||||
buildFormData: (file) =>
|
||||
formData = new FormData()
|
||||
formData.append('csrfmiddlewaretoken', @options.csrfToken)
|
||||
formData.append('file', file)
|
||||
formData.append(@meta.fieldName, file)
|
||||
return formData
|
||||
|
||||
addFile: (data, file, placeholder) =>
|
||||
# format as a link to the file
|
||||
fileTag = $.format("[{name}]({url})", {name: file.name, url: data.url})
|
||||
@textReplace(placeholder, fileTag)
|
||||
imageTag = $.format(@meta.tag, {text: file.name, url: data.url})
|
||||
@textReplace(placeholder, imageTag)
|
||||
|
||||
addError: (data, placeholder) =>
|
||||
error = JSON.stringify(data)
|
||||
@textReplace(placeholder, "[#{ error }]()")
|
||||
@textReplace(
|
||||
placeholder,
|
||||
$.format(@meta.tag, {text: error, url: ""}))
|
||||
|
||||
addStatusError: (textStatus, error, placeholder) =>
|
||||
errorTag = $.format("[error: {code} {error}]()", {code: textStatus, error: error})
|
||||
errorTag = $.format(@meta.tag, {
|
||||
text: $.format("error: {code} {error}", {
|
||||
code: textStatus,
|
||||
error: error}),
|
||||
url: ""})
|
||||
@textReplace(placeholder, errorTag)
|
||||
|
||||
textReplace: (find, replace) =>
|
||||
|
@ -112,7 +122,14 @@ $.fn.extend
|
|||
editor_file_upload: (options) ->
|
||||
@each( ->
|
||||
if not $(@).data('plugin_editor_file_upload')
|
||||
$(@).data('plugin_editor_file_upload', new EditorFileUpload(@, options))
|
||||
$(@).data('plugin_editor_file_upload', new EditorUpload(@, options))
|
||||
)
|
||||
editor_image_upload: (options) ->
|
||||
@each( ->
|
||||
if not $(@).data('plugin_editor_image_upload')
|
||||
$(@).data('plugin_editor_image_upload', new EditorUpload(@, options, {
|
||||
fieldName: "image",
|
||||
tag: "![{text}]({url})",
|
||||
elm: ".js-box-image"
|
||||
}))
|
||||
)
|
||||
|
||||
$.fn.editor_file_upload.EditorFileUpload = EditorFileUpload
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
###
|
||||
Markdown editor image upload, should be loaded before $.editor()
|
||||
requires: util.js
|
||||
###
|
||||
|
||||
$ = jQuery
|
||||
|
||||
|
||||
class EditorImageUpload
|
||||
|
||||
defaults: {
|
||||
csrfToken: "csrf_token",
|
||||
target: "target url",
|
||||
placeholderText: "uploading {image_name}"
|
||||
}
|
||||
|
||||
constructor: (el, options) ->
|
||||
@el = $(el)
|
||||
@options = $.extend({}, @defaults, options)
|
||||
@formFile = $("<form/>")
|
||||
@inputFile = $("<input/>", {
|
||||
type: "file",
|
||||
accept: "image/*"}).appendTo(@formFile)
|
||||
@setUp()
|
||||
|
||||
setUp: ->
|
||||
if not window.FormData?
|
||||
return
|
||||
|
||||
@inputFile.on('change', @sendFile)
|
||||
|
||||
# TODO: fixme, having multiple editors
|
||||
# in the same page would open several
|
||||
# dialogs on box-image click
|
||||
$boxImage = $(".js-box-image")
|
||||
$boxImage.on('click', @openFileDialog)
|
||||
$boxImage.on('click', @stopClick)
|
||||
|
||||
sendFile: =>
|
||||
file = @inputFile.get(0).files[0]
|
||||
placeholder = @addPlaceholder(file)
|
||||
formData = @buildFormData(file)
|
||||
|
||||
post = $.ajax({
|
||||
url: @options.target,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST'
|
||||
})
|
||||
|
||||
post.done((data) =>
|
||||
if "url" of data
|
||||
@addImage(data, file, placeholder)
|
||||
else
|
||||
@addError(data, placeholder)
|
||||
)
|
||||
|
||||
post.fail((jqxhr, textStatus, error) =>
|
||||
@addStatusError(textStatus, error, placeholder)
|
||||
)
|
||||
|
||||
post.always(() =>
|
||||
# Reset the input after uploading,
|
||||
# fixes uploading the same image twice
|
||||
@formFile.get(0).reset()
|
||||
)
|
||||
|
||||
return
|
||||
|
||||
addPlaceholder: (file) =>
|
||||
placeholder = $.format("![#{ @options.placeholderText }]()", {image_name: file.name, })
|
||||
@el.val(@el.val() + placeholder)
|
||||
return placeholder
|
||||
|
||||
buildFormData: (file) =>
|
||||
formData = new FormData()
|
||||
formData.append('csrfmiddlewaretoken', @options.csrfToken)
|
||||
formData.append('image', file)
|
||||
return formData
|
||||
|
||||
addImage: (data, file, placeholder) =>
|
||||
imageTag = $.format("![{name}]({url})", {name: file.name, url: data.url})
|
||||
@textReplace(placeholder, imageTag)
|
||||
|
||||
addError: (data, placeholder) =>
|
||||
error = JSON.stringify(data)
|
||||
@textReplace(placeholder, "![#{ error }]()")
|
||||
|
||||
addStatusError: (textStatus, error, placeholder) =>
|
||||
errorTag = $.format("![error: {code} {error}]()", {code: textStatus, error: error})
|
||||
@textReplace(placeholder, errorTag)
|
||||
|
||||
textReplace: (find, replace) =>
|
||||
@el.val(@el.val().replace(find, replace))
|
||||
return
|
||||
|
||||
openFileDialog: =>
|
||||
@inputFile.trigger('click')
|
||||
return
|
||||
|
||||
stopClick: (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
e.stopImmediatePropagation()
|
||||
return
|
||||
|
||||
|
||||
$.fn.extend
|
||||
editor_image_upload: (options) ->
|
||||
@each( ->
|
||||
if not $(@).data('plugin_editor_image_upload')
|
||||
$(@).data('plugin_editor_image_upload', new EditorImageUpload(@, options))
|
||||
)
|
||||
|
||||
$.fn.editor_image_upload.EditorImageUpload = EditorImageUpload
|
File diff suppressed because one or more lines are too long
|
@ -14,9 +14,7 @@ describe "editor plugin tests", ->
|
|||
linkText: "foo link text",
|
||||
linkUrlText: "foo link url",
|
||||
imageText: "foo image text",
|
||||
imageUrlText: "foo image url",
|
||||
fileText: "foo file text",
|
||||
fileUrlText: "foo file url"
|
||||
imageUrlText: "foo image url"
|
||||
}
|
||||
editor = textarea.data 'plugin_editor'
|
||||
|
||||
|
@ -53,10 +51,6 @@ describe "editor plugin tests", ->
|
|||
$('.js-box-image').trigger 'click'
|
||||
expect(textarea.val()).toEqual "![foo image text](foo image url)"
|
||||
|
||||
it "adds file", ->
|
||||
$('.js-box-file').trigger 'click'
|
||||
expect(textarea.val()).toEqual "[foo file text](foo file url)"
|
||||
|
||||
it "adds all", ->
|
||||
$('.js-box-bold').trigger 'click'
|
||||
$('.js-box-italic').trigger 'click'
|
||||
|
@ -106,14 +100,6 @@ describe "editor plugin tests", ->
|
|||
$('.js-box-image').trigger 'click'
|
||||
expect(textarea.val()).toEqual "bir![foo](foo image url)bar"
|
||||
|
||||
it "wraps the selected text, file", ->
|
||||
textarea.val "birfoobar"
|
||||
textarea.first()[0].selectionStart = 3
|
||||
textarea.first()[0].selectionEnd = 6
|
||||
|
||||
$('.js-box-file').trigger 'click'
|
||||
expect(textarea.val()).toEqual "bir[foo](foo file url)bar"
|
||||
|
||||
it "shows html preview", ->
|
||||
textarea.val "*foo*"
|
||||
$('.js-box-preview').trigger 'click'
|
||||
|
|
|
@ -56,7 +56,8 @@
|
|||
$('.js-box-italic').trigger('click');
|
||||
$('.js-box-list').trigger('click');
|
||||
$('.js-box-url').trigger('click');
|
||||
return $('.js-box-image').trigger('click');
|
||||
$('.js-box-image').trigger('click');
|
||||
return $('.js-box-file').trigger('click');
|
||||
});
|
||||
it("wraps the selected text, bold", function() {
|
||||
textarea.val("birfoobar");
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -26,7 +26,8 @@ describe "editor file upload plugin tests", ->
|
|||
textarea = $('#id_comment').editor_file_upload {
|
||||
csrfToken: "foo csrf_token",
|
||||
target: "/foo/",
|
||||
placeholderText: "foo uploading {file_name}"
|
||||
placeholderText: "foo uploading {name}",
|
||||
allowedFileMedia: ".doc,.docx,.pdf"
|
||||
}
|
||||
editorFileUpload = textarea.first().data 'plugin_editor_file_upload'
|
||||
inputFile = editorFileUpload.inputFile
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
(function() {
|
||||
describe("editor file upload plugin tests", function() {
|
||||
var data, editorFileUpload, file, inputFile, post, textarea;
|
||||
textarea = null;
|
||||
editorFileUpload = null;
|
||||
data = null;
|
||||
inputFile = null;
|
||||
file = null;
|
||||
post = null;
|
||||
beforeEach(function() {
|
||||
var fixtures;
|
||||
fixtures = jasmine.getFixtures();
|
||||
fixtures.fixturesPath = 'base/test/fixtures/';
|
||||
loadFixtures('editor.html');
|
||||
post = spyOn($, 'ajax');
|
||||
post.and.callFake(function(req) {
|
||||
var d;
|
||||
d = $.Deferred();
|
||||
d.resolve(data);
|
||||
return d.promise();
|
||||
});
|
||||
data = {
|
||||
url: "/path/file.pdf"
|
||||
};
|
||||
file = {
|
||||
name: "foo.pdf"
|
||||
};
|
||||
textarea = $('#id_comment').editor_file_upload({
|
||||
csrfToken: "foo csrf_token",
|
||||
target: "/foo/",
|
||||
placeholderText: "foo uploading {name}",
|
||||
allowedFileMedia: ".doc,.docx,.pdf"
|
||||
});
|
||||
editorFileUpload = textarea.first().data('plugin_editor_file_upload');
|
||||
return inputFile = editorFileUpload.inputFile;
|
||||
});
|
||||
it("doesnt break selector chaining", function() {
|
||||
expect(textarea).toEqual($('#id_comment'));
|
||||
return expect(textarea.length).toEqual(1);
|
||||
});
|
||||
it("does nothing if the browser is not supported", function() {
|
||||
var inputFile2, org_formData, textarea2, trigger;
|
||||
org_formData = window.FormData;
|
||||
window.FormData = null;
|
||||
try {
|
||||
$(".js-box-file").off('click');
|
||||
textarea2 = $('#id_comment2').editor_file_upload();
|
||||
inputFile2 = textarea2.data('plugin_editor_file_upload').inputFile;
|
||||
trigger = spyOn(inputFile2, 'trigger');
|
||||
$(".js-box-file").trigger('click');
|
||||
return expect(trigger).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
window.FormData = org_formData;
|
||||
}
|
||||
});
|
||||
it("opens the file choose dialog", function() {
|
||||
var trigger;
|
||||
trigger = spyOn(inputFile, 'trigger');
|
||||
$(".js-box-file").trigger('click');
|
||||
return expect(trigger).toHaveBeenCalled();
|
||||
});
|
||||
it("uploads the file", function() {
|
||||
var formDataMock;
|
||||
expect($.ajax.calls.any()).toEqual(false);
|
||||
formDataMock = jasmine.createSpyObj('formDataMock', ['append']);
|
||||
spyOn(window, "FormData").and.returnValue(formDataMock);
|
||||
spyOn(inputFile, 'get').and.returnValue({
|
||||
files: [file]
|
||||
});
|
||||
inputFile.trigger('change');
|
||||
expect($.ajax.calls.any()).toEqual(true);
|
||||
expect($.ajax.calls.argsFor(0)).toEqual([
|
||||
{
|
||||
url: '/foo/',
|
||||
data: formDataMock,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
type: 'POST'
|
||||
}
|
||||
]);
|
||||
expect(formDataMock.append).toHaveBeenCalledWith('csrfmiddlewaretoken', 'foo csrf_token');
|
||||
return expect(formDataMock.append).toHaveBeenCalledWith('file', {
|
||||
name: 'foo.pdf'
|
||||
});
|
||||
});
|
||||
it("changes the placeholder on upload success", function() {
|
||||
textarea.val("foobar");
|
||||
spyOn(inputFile, 'get').and.returnValue({
|
||||
files: [file]
|
||||
});
|
||||
inputFile.trigger('change');
|
||||
return expect(textarea.val()).toEqual("foobar[foo.pdf](/path/file.pdf)");
|
||||
});
|
||||
it("changes the placeholder on upload error", function() {
|
||||
textarea.val("foobar");
|
||||
data = {
|
||||
error: {
|
||||
foo: "foo error"
|
||||
}
|
||||
};
|
||||
spyOn(inputFile, 'get').and.returnValue({
|
||||
files: [file]
|
||||
});
|
||||
inputFile.trigger('change');
|
||||
return expect(textarea.val()).toEqual("foobar[{\"error\":{\"foo\":\"foo error\"}}]()");
|
||||
});
|
||||
it("changes the placeholder on upload failure", function() {
|
||||
var d;
|
||||
textarea.val("foobar");
|
||||
d = $.Deferred();
|
||||
post.and.callFake(function(req) {
|
||||
d.reject(null, "foo statusError", "bar error");
|
||||
return d.promise();
|
||||
});
|
||||
spyOn(inputFile, 'get').and.returnValue({
|
||||
files: [file]
|
||||
});
|
||||
inputFile.trigger('change');
|
||||
return expect(textarea.val()).toEqual("foobar[error: foo statusError bar error]()");
|
||||
});
|
||||
it("checks for default media file extensions if none are provided", function() {
|
||||
return expect(inputFile[0].outerHTML).toContain(".doc,.docx,.pdf");
|
||||
});
|
||||
return it("checks for custom media file extensions if they are provided", function() {
|
||||
var editorFileUpload3, inputFile3, textarea3;
|
||||
textarea3 = $('#id_comment3').editor_file_upload({
|
||||
csrfToken: "foo csrf_token",
|
||||
target: "/foo/",
|
||||
placeholderText: "foo uploading {file_name}",
|
||||
allowedFileMedia: [".superdoc"]
|
||||
});
|
||||
editorFileUpload3 = textarea3.first().data('plugin_editor_file_upload');
|
||||
inputFile3 = editorFileUpload3.inputFile;
|
||||
expect(inputFile3[0].outerHTML).not.toContain(".doc,.docx,.pdf");
|
||||
return expect(inputFile3[0].outerHTML).toContain(".superdoc");
|
||||
});
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
|
||||
//# sourceMappingURL=editor_file_upload-spec.js.map
|
File diff suppressed because one or more lines are too long
|
@ -26,7 +26,7 @@ describe "editor image upload plugin tests", ->
|
|||
textarea = $('#id_comment').editor_image_upload {
|
||||
csrfToken: "foo csrf_token",
|
||||
target: "/foo/",
|
||||
placeholderText: "foo uploading {image_name}"
|
||||
placeholderText: "foo uploading {name}"
|
||||
}
|
||||
editorImageUpload = textarea.first().data 'plugin_editor_image_upload'
|
||||
inputFile = editorImageUpload.inputFile
|
||||
|
@ -71,12 +71,15 @@ describe "editor image upload plugin tests", ->
|
|||
it "adds the placeholder", ->
|
||||
textarea.val "foobar"
|
||||
|
||||
ajaxMock = jasmine.createSpyObj('ajax', ['done', 'fail'])
|
||||
post.and.returnValue ajaxMock
|
||||
post.and.callFake (req) ->
|
||||
expect(textarea.val()).toEqual "foobar![foo uploading foo.jpg]()"
|
||||
|
||||
d = $.Deferred()
|
||||
d.resolve(data)
|
||||
return d.promise()
|
||||
|
||||
spyOn(inputFile, 'get').and.returnValue {files: [file, ]}
|
||||
inputFile.trigger 'change'
|
||||
expect(textarea.val()).toEqual "foobar![foo uploading foo.jpg]()"
|
||||
|
||||
it "changes the placeholder on upload success", ->
|
||||
textarea.val "foobar"
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
textarea = $('#id_comment').editor_image_upload({
|
||||
csrfToken: "foo csrf_token",
|
||||
target: "/foo/",
|
||||
placeholderText: "foo uploading {image_name}"
|
||||
placeholderText: "foo uploading {name}"
|
||||
});
|
||||
editorImageUpload = textarea.first().data('plugin_editor_image_upload');
|
||||
return inputFile = editorImageUpload.inputFile;
|
||||
|
@ -83,15 +83,18 @@
|
|||
});
|
||||
});
|
||||
it("adds the placeholder", function() {
|
||||
var ajaxMock;
|
||||
textarea.val("foobar");
|
||||
ajaxMock = jasmine.createSpyObj('ajax', ['done', 'fail']);
|
||||
post.and.returnValue(ajaxMock);
|
||||
post.and.callFake(function(req) {
|
||||
var d;
|
||||
expect(textarea.val()).toEqual("foobar![foo uploading foo.jpg]()");
|
||||
d = $.Deferred();
|
||||
d.resolve(data);
|
||||
return d.promise();
|
||||
});
|
||||
spyOn(inputFile, 'get').and.returnValue({
|
||||
files: [file]
|
||||
});
|
||||
inputFile.trigger('change');
|
||||
return expect(textarea.val()).toEqual("foobar![foo uploading foo.jpg]()");
|
||||
return inputFile.trigger('change');
|
||||
});
|
||||
it("changes the placeholder on upload success", function() {
|
||||
textarea.val("foobar");
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,4 +2,4 @@ describe "editor plugin tests", ->
|
|||
|
||||
it "returns the emoji list", ->
|
||||
emojis = $.emoji_list()
|
||||
expect(emojis[0]).toEqual "+1"
|
||||
expect(emojis[0]).toEqual {"name": "+1"}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
return it("returns the emoji list", function() {
|
||||
var emojis;
|
||||
emojis = $.emoji_list();
|
||||
return expect(emojis[0]).toEqual("+1");
|
||||
return expect(emojis[0]).toEqual({
|
||||
"name": "+1"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["emoji_list-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,qBAAT,EAAgC,SAAA;WAE5B,EAAA,CAAG,wBAAH,EAA6B,SAAA;AACzB,UAAA;MAAA,MAAA,GAAS,CAAC,CAAC,UAAF,CAAA;aACT,MAAA,CAAO,MAAO,CAAA,CAAA,CAAd,CAAiB,CAAC,OAAlB,CAA0B,IAA1B;IAFyB,CAA7B;EAF4B,CAAhC;AAAA","file":"emoji_list-spec.js","sourceRoot":"/source/","sourcesContent":["describe \"editor plugin tests\", ->\n\n it \"returns the emoji list\", ->\n emojis = $.emoji_list()\n expect(emojis[0]).toEqual \"+1\"\n"]}
|
||||
{"version":3,"file":"emoji_list-spec.js","sources":["emoji_list-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,qBAAT,EAAgC,SAAA;WAE5B,EAAA,CAAG,wBAAH,EAA6B,SAAA;AACzB,UAAA;MAAA,MAAA,GAAS,CAAC,CAAC,UAAF,CAAA;aACT,MAAA,CAAO,MAAO,CAAA,CAAA,CAAd,CAAiB,CAAC,OAAlB,CAA0B;QAAC,MAAA,EAAQ,IAAT;OAA1B;IAFyB,CAA7B;EAF4B,CAAhC;AAAA","sourcesContent":["describe \"editor plugin tests\", ->\n\n it \"returns the emoji list\", ->\n emojis = $.emoji_list()\n expect(emojis[0]).toEqual {\"name\": \"+1\"}\n"]}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["postify-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,sBAAT,EAAiC,SAAA;AAC7B,QAAA;IAAA,MAAA,GAAS;IACT,cAAA,GAAiB;IACjB,OAAA,GAAU;IAEV,UAAA,CAAW,SAAA;AACP,UAAA;MAAA,QAAA,GAAc,OAAO,CAAC,WAAX,CAAA;MACX,QAAQ,CAAC,YAAT,GAAwB;MACxB,YAAA,CAAa,cAAb;MAEA,MAAA,GAAS,CAAA,CAAE,WAAF,CAAc,CAAC,OAAf,CAAuB;QAAC,SAAA,EAAW,QAAZ;OAAvB;MACT,cAAA,GAAiB,MAAM,CAAC,KAAP,CAAA,CAAc,CAAC,IAAf,CAAoB,gBAApB;aACjB,OAAA,GAAU,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;IAPhB,CAAX;IASA,EAAA,CAAG,gCAAH,EAAqC,SAAA;MACjC,MAAA,CAAO,MAAP,CAAc,CAAC,OAAf,CAAuB,CAAA,CAAE,UAAF,CAAvB;aACA,MAAA,CAAO,MAAM,CAAC,MAAd,CAAqB,CAAC,OAAtB,CAA8B,CAA9B;IAFiC,CAArC;IAIA,EAAA,CAAG,+CAAH,EAAoD,SAAA;AAChD,UAAA;MAAA,KAAA,GAAQ;QAAC,IAAA,EAAM,OAAP;QAAgB,eAAA,EAAiB,CAAC,SAAA,GAAA,CAAD,CAAjC;QAAuC,cAAA,EAAgB,CAAC,SAAA,GAAA,CAAD,CAAvD;;MACR,eAAA,GAAkB,KAAA,CAAM,KAAN,EAAa,iBAAb;MAClB,cAAA,GAAiB,KAAA,CAAM,KAAN,EAAa,gBAAb;MAEjB,KAAA,CAAM,cAAN,EAAsB,YAAtB;MACA,CAAA,CAAE,UAAF,CAAa,CAAC,KAAd,CAAA,CAAqB,CAAC,OAAtB,CAA8B,KAA9B;MACA,MAAA,CAAO,eAAP,CAAuB,CAAC,gBAAxB,CAAA;aACA,MAAA,CAAO,cAAP,CAAsB,CAAC,gBAAvB,CAAA;IARgD,CAApD;WAUA,EAAA,CAAG,kBAAH,EAAuB,SAAA;AACnB,UAAA;MAAA,UAAA,GAAa,KAAA,CAAM,cAAN,EAAsB,YAAtB;MAEb,CAAA,CAAE,UAAF,CAAa,CAAC,KAAd,CAAA,CAAqB,CAAC,OAAtB,CAA8B,OAA9B;MACA,MAAA,CAAO,UAAP,CAAkB,CAAC,gBAAnB,CAAA;MACA,MAAA,CAAO,CAAA,CAAE,MAAF,CAAS,CAAC,IAAV,CAAA,CAAgB,CAAC,IAAjB,CAAsB,QAAtB,CAAP,CAAuC,CAAC,OAAxC,CAAgD,SAAhD;MACA,MAAA,CAAO,CAAA,CAAE,MAAF,CAAS,CAAC,IAAV,CAAA,CAAgB,CAAC,EAAjB,CAAoB,UAApB,CAAP,CAAsC,CAAC,OAAvC,CAA+C,KAA/C;aACA,MAAA,CAAO,CAAA,CAAE,iCAAF,CAAoC,CAAC,GAArC,CAAA,CAAP,CAAkD,CAAC,OAAnD,CAA2D,QAA3D;IAPmB,CAAvB;EA5B6B,CAAjC;AAAA","file":"postify-spec.js","sourceRoot":"/source/","sourcesContent":["describe \"postify plugin tests\", ->\n a_post = null\n plugin_postify = null\n Postify = null\n\n beforeEach ->\n fixtures = do jasmine.getFixtures\n fixtures.fixturesPath = 'base/test/fixtures/'\n loadFixtures 'postify.html'\n\n a_post = $('a.js-post').postify {csrfToken: \"foobar\", }\n plugin_postify = a_post.first().data 'plugin_postify'\n Postify = $.fn.postify.Postify\n\n it \"doesnt break selector chaining\", ->\n expect(a_post).toEqual $('.js-post')\n expect(a_post.length).toEqual 2\n\n it \"prevents the default click behaviour on click\", ->\n event = {type: 'click', stopPropagation: (->), preventDefault: (->)}\n stopPropagation = spyOn event, 'stopPropagation'\n preventDefault = spyOn event, 'preventDefault'\n\n spyOn plugin_postify, 'formSubmit'\n $(\".js-post\").first().trigger event\n expect(stopPropagation).toHaveBeenCalled()\n expect(preventDefault).toHaveBeenCalled()\n\n it \"submits the form\", ->\n formSubmit = spyOn plugin_postify, 'formSubmit'\n\n $('.js-post').first().trigger 'click'\n expect(formSubmit).toHaveBeenCalled()\n expect($(\"form\").last().attr('action')).toEqual \"/link1/\"\n expect($(\"form\").last().is \":visible\").toEqual false\n expect($(\"input[name=csrfmiddlewaretoken]\").val()).toEqual \"foobar\"\n"]}
|
||||
{"version":3,"file":"postify-spec.js","sources":["postify-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,sBAAT,EAAiC,SAAA;AAC7B,QAAA;IAAA,MAAA,GAAS;IACT,cAAA,GAAiB;IACjB,OAAA,GAAU;IAEV,UAAA,CAAW,SAAA;AACP,UAAA;MAAA,QAAA,GAAc,OAAO,CAAC,WAAX,CAAA;MACX,QAAQ,CAAC,YAAT,GAAwB;MACxB,YAAA,CAAa,cAAb;MAEA,MAAA,GAAS,CAAA,CAAE,WAAF,CAAc,CAAC,OAAf,CAAuB;QAAC,SAAA,EAAW,QAAZ;OAAvB;MACT,cAAA,GAAiB,MAAM,CAAC,KAAP,CAAA,CAAc,CAAC,IAAf,CAAoB,gBAApB;aACjB,OAAA,GAAU,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;IAPhB,CAAX;IASA,EAAA,CAAG,gCAAH,EAAqC,SAAA;MACjC,MAAA,CAAO,MAAP,CAAc,CAAC,OAAf,CAAuB,CAAA,CAAE,UAAF,CAAvB;aACA,MAAA,CAAO,MAAM,CAAC,MAAd,CAAqB,CAAC,OAAtB,CAA8B,CAA9B;IAFiC,CAArC;IAIA,EAAA,CAAG,+CAAH,EAAoD,SAAA;AAChD,UAAA;MAAA,KAAA,GAAQ;QAAC,IAAA,EAAM,OAAP;QAAgB,eAAA,EAAiB,CAAC,SAAA,GAAA,CAAD,CAAjC;QAAuC,cAAA,EAAgB,CAAC,SAAA,GAAA,CAAD,CAAvD;;MACR,eAAA,GAAkB,KAAA,CAAM,KAAN,EAAa,iBAAb;MAClB,cAAA,GAAiB,KAAA,CAAM,KAAN,EAAa,gBAAb;MAEjB,KAAA,CAAM,cAAN,EAAsB,YAAtB;MACA,CAAA,CAAE,UAAF,CAAa,CAAC,KAAd,CAAA,CAAqB,CAAC,OAAtB,CAA8B,KAA9B;MACA,MAAA,CAAO,eAAP,CAAuB,CAAC,gBAAxB,CAAA;aACA,MAAA,CAAO,cAAP,CAAsB,CAAC,gBAAvB,CAAA;IARgD,CAApD;WAUA,EAAA,CAAG,kBAAH,EAAuB,SAAA;AACnB,UAAA;MAAA,UAAA,GAAa,KAAA,CAAM,cAAN,EAAsB,YAAtB;MAEb,CAAA,CAAE,UAAF,CAAa,CAAC,KAAd,CAAA,CAAqB,CAAC,OAAtB,CAA8B,OAA9B;MACA,MAAA,CAAO,UAAP,CAAkB,CAAC,gBAAnB,CAAA;MACA,MAAA,CAAO,CAAA,CAAE,MAAF,CAAS,CAAC,IAAV,CAAA,CAAgB,CAAC,IAAjB,CAAsB,QAAtB,CAAP,CAAuC,CAAC,OAAxC,CAAgD,SAAhD;MACA,MAAA,CAAO,CAAA,CAAE,MAAF,CAAS,CAAC,IAAV,CAAA,CAAgB,CAAC,EAAjB,CAAoB,UAApB,CAAP,CAAsC,CAAC,OAAvC,CAA+C,KAA/C;aACA,MAAA,CAAO,CAAA,CAAE,iCAAF,CAAoC,CAAC,GAArC,CAAA,CAAP,CAAkD,CAAC,OAAnD,CAA2D,QAA3D;IAPmB,CAAvB;EA5B6B,CAAjC;AAAA","sourcesContent":["describe \"postify plugin tests\", ->\n a_post = null\n plugin_postify = null\n Postify = null\n\n beforeEach ->\n fixtures = do jasmine.getFixtures\n fixtures.fixturesPath = 'base/test/fixtures/'\n loadFixtures 'postify.html'\n\n a_post = $('a.js-post').postify {csrfToken: \"foobar\", }\n plugin_postify = a_post.first().data 'plugin_postify'\n Postify = $.fn.postify.Postify\n\n it \"doesnt break selector chaining\", ->\n expect(a_post).toEqual $('.js-post')\n expect(a_post.length).toEqual 2\n\n it \"prevents the default click behaviour on click\", ->\n event = {type: 'click', stopPropagation: (->), preventDefault: (->)}\n stopPropagation = spyOn event, 'stopPropagation'\n preventDefault = spyOn event, 'preventDefault'\n\n spyOn plugin_postify, 'formSubmit'\n $(\".js-post\").first().trigger event\n expect(stopPropagation).toHaveBeenCalled()\n expect(preventDefault).toHaveBeenCalled()\n\n it \"submits the form\", ->\n formSubmit = spyOn plugin_postify, 'formSubmit'\n\n $('.js-post').first().trigger 'click'\n expect(formSubmit).toHaveBeenCalled()\n expect($(\"form\").last().attr('action')).toEqual \"/link1/\"\n expect($(\"form\").last().is \":visible\").toEqual false\n expect($(\"input[name=csrfmiddlewaretoken]\").val()).toEqual \"foobar\"\n"]}
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["store-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,oBAAT,EAA+B,SAAA;AAC3B,QAAA;IAAA,QAAA,GAAW;IACX,OAAA,GAAU;IAEV,UAAA,CAAW,SAAA;AACP,UAAA;MAAA,QAAA,GAAc,OAAO,CAAC,WAAX,CAAA;MACX,QAAQ,CAAC,YAAT,GAAwB;MACxB,YAAA,CAAa,YAAb;MAEG,YAAY,CAAC,KAAhB,CAAA;MACA,QAAA,GAAW,CAAA,CAAE,aAAF,CAAgB,CAAC,KAAjB,CAAuB,WAAvB;aACX,OAAA,GAAU,QAAQ,CAAC,IAAT,CAAc,cAAd;IAPH,CAAX;IASA,EAAA,CAAG,gCAAH,EAAqC,SAAA;aACjC,MAAA,CAAO,QAAP,CAAgB,CAAC,OAAjB,CAAyB,CAAA,CAAE,aAAF,CAAzB;IADiC,CAArC;IAGA,EAAA,CAAG,6BAAH,EAAkC,SAAA;MAC9B,YAAa,CAAA,WAAA,CAAb,GAA4B;MAC5B,QAAA,GAAW,CAAA,CAAE,eAAF,CAAkB,CAAC,KAAnB,CAAyB,WAAzB;aACX,MAAA,CAAO,QAAP,CAAgB,CAAC,WAAjB,CAA6B,MAA7B;IAH8B,CAAlC;IAKA,EAAA,CAAG,qCAAH,EAA0C,SAAA;MACtC,YAAa,CAAA,WAAA,CAAb,GAA4B;MAC5B,CAAA,CAAE,MAAF,CAAS,CAAC,OAAV,CAAkB,SAAlB;aACA,MAAA,CAAO,QAAP,CAAgB,CAAC,WAAjB,CAA6B,MAA7B;IAHsC,CAA1C;IAKA,EAAA,CAAG,sCAAH,EAA2C,SAAA;MACvC,QAAQ,CAAC,GAAT,CAAa,QAAb;MACA,QAAQ,CAAC,OAAT,CAAiB,OAAjB;aACA,MAAA,CAAO,YAAa,CAAA,WAAA,CAApB,CAAiC,CAAC,OAAlC,CAA0C,QAA1C;IAHuC,CAA3C;IAKA,EAAA,CAAG,oCAAH,EAAyC,SAAA;MACrC,KAAA,CAAM,OAAN,EAAe,aAAf;MACA,QAAQ,CAAC,OAAT,CAAiB,OAAjB;aACA,MAAA,CAAO,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,KAA1B,CAAA,CAAP,CAAyC,CAAC,OAA1C,CAAkD,CAAlD;IAHqC,CAAzC;WAKA,EAAA,CAAG,wBAAH,EAA6B,SAAA;AACzB,UAAA;MAAA,YAAa,CAAA,WAAA,CAAb,GAA4B;MAC5B,cAAA,GAAiB,OAAO,CAAC,SAAR,CAAkB,gBAAlB,CAAmC,CAAC,GAAG,CAAC,WAAxC,CAAoD,KAApD;MACjB,KAAA,GAAQ,CAAA,CAAE,MAAF;MACR,KAAK,CAAC,EAAN,CAAS,QAAT,EAAmB,cAAnB;MACA,KAAK,CAAC,OAAN,CAAc,QAAd;MACA,MAAA,CAAO,WAAA,IAAe,YAAtB,CAAmC,CAAC,IAApC,CAAyC,KAAzC;aACA,MAAA,CAAO,cAAP,CAAsB,CAAC,gBAAvB,CAAA;IAPyB,CAA7B;EApC2B,CAA/B;AAAA","file":"store-spec.js","sourceRoot":"/source/","sourcesContent":["describe \"store plugin tests\", ->\n textarea = null\n storage = null\n\n beforeEach ->\n fixtures = do jasmine.getFixtures\n fixtures.fixturesPath = 'base/test/fixtures/'\n loadFixtures 'store.html'\n\n do localStorage.clear\n textarea = $('#my-fixture').store 'unique-id'\n storage = textarea.data 'plugin_store'\n\n it \"doesnt break selector chaining\", ->\n expect(textarea).toEqual $('#my-fixture')\n\n it \"loads previous stored value\", ->\n localStorage['unique-id'] = \"text\"\n textarea = $('#my-fixture-2').store 'unique-id'\n expect(textarea).toHaveValue \"text\"\n\n it \"updates the field on storage change\", ->\n localStorage['unique-id'] = \"text\"\n $(window).trigger \"storage\"\n expect(textarea).toHaveValue \"text\"\n\n it \"saves value to localStorage on input\", ->\n textarea.val \"foobar\"\n textarea.trigger 'input'\n expect(localStorage['unique-id']).toEqual \"foobar\"\n\n it \"wont (re)update the field on input\", ->\n spyOn storage, 'updateField'\n textarea.trigger 'input'\n expect(storage.updateField.calls.count()).toEqual 0\n\n it \"gets cleared on submit\", ->\n localStorage['unique-id'] = \"foo\"\n submitCallback = jasmine.createSpy('submitCallback').and.returnValue false\n $form = $('form')\n $form.on 'submit', submitCallback\n $form.trigger \"submit\"\n expect('unique-id' of localStorage).toBe false\n expect(submitCallback).toHaveBeenCalled()\n"]}
|
||||
{"version":3,"file":"store-spec.js","sources":["store-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,oBAAT,EAA+B,SAAA;AAC3B,QAAA;IAAA,QAAA,GAAW;IACX,OAAA,GAAU;IAEV,UAAA,CAAW,SAAA;AACP,UAAA;MAAA,QAAA,GAAc,OAAO,CAAC,WAAX,CAAA;MACX,QAAQ,CAAC,YAAT,GAAwB;MACxB,YAAA,CAAa,YAAb;MAEG,YAAY,CAAC,KAAhB,CAAA;MACA,QAAA,GAAW,CAAA,CAAE,aAAF,CAAgB,CAAC,KAAjB,CAAuB,WAAvB;aACX,OAAA,GAAU,QAAQ,CAAC,IAAT,CAAc,cAAd;IAPH,CAAX;IASA,EAAA,CAAG,gCAAH,EAAqC,SAAA;aACjC,MAAA,CAAO,QAAP,CAAgB,CAAC,OAAjB,CAAyB,CAAA,CAAE,aAAF,CAAzB;IADiC,CAArC;IAGA,EAAA,CAAG,6BAAH,EAAkC,SAAA;MAC9B,YAAa,CAAA,WAAA,CAAb,GAA4B;MAC5B,QAAA,GAAW,CAAA,CAAE,eAAF,CAAkB,CAAC,KAAnB,CAAyB,WAAzB;aACX,MAAA,CAAO,QAAP,CAAgB,CAAC,WAAjB,CAA6B,MAA7B;IAH8B,CAAlC;IAKA,EAAA,CAAG,qCAAH,EAA0C,SAAA;MACtC,YAAa,CAAA,WAAA,CAAb,GAA4B;MAC5B,CAAA,CAAE,MAAF,CAAS,CAAC,OAAV,CAAkB,SAAlB;aACA,MAAA,CAAO,QAAP,CAAgB,CAAC,WAAjB,CAA6B,MAA7B;IAHsC,CAA1C;IAKA,EAAA,CAAG,sCAAH,EAA2C,SAAA;MACvC,QAAQ,CAAC,GAAT,CAAa,QAAb;MACA,QAAQ,CAAC,OAAT,CAAiB,OAAjB;aACA,MAAA,CAAO,YAAa,CAAA,WAAA,CAApB,CAAiC,CAAC,OAAlC,CAA0C,QAA1C;IAHuC,CAA3C;IAKA,EAAA,CAAG,oCAAH,EAAyC,SAAA;MACrC,KAAA,CAAM,OAAN,EAAe,aAAf;MACA,QAAQ,CAAC,OAAT,CAAiB,OAAjB;aACA,MAAA,CAAO,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,KAA1B,CAAA,CAAP,CAAyC,CAAC,OAA1C,CAAkD,CAAlD;IAHqC,CAAzC;WAKA,EAAA,CAAG,wBAAH,EAA6B,SAAA;AACzB,UAAA;MAAA,YAAa,CAAA,WAAA,CAAb,GAA4B;MAC5B,cAAA,GAAiB,OAAO,CAAC,SAAR,CAAkB,gBAAlB,CAAmC,CAAC,GAAG,CAAC,WAAxC,CAAoD,KAApD;MACjB,KAAA,GAAQ,CAAA,CAAE,MAAF;MACR,KAAK,CAAC,EAAN,CAAS,QAAT,EAAmB,cAAnB;MACA,KAAK,CAAC,OAAN,CAAc,QAAd;MACA,MAAA,CAAO,WAAA,IAAe,YAAtB,CAAmC,CAAC,IAApC,CAAyC,KAAzC;aACA,MAAA,CAAO,cAAP,CAAsB,CAAC,gBAAvB,CAAA;IAPyB,CAA7B;EApC2B,CAA/B;AAAA","sourcesContent":["describe \"store plugin tests\", ->\n textarea = null\n storage = null\n\n beforeEach ->\n fixtures = do jasmine.getFixtures\n fixtures.fixturesPath = 'base/test/fixtures/'\n loadFixtures 'store.html'\n\n do localStorage.clear\n textarea = $('#my-fixture').store 'unique-id'\n storage = textarea.data 'plugin_store'\n\n it \"doesnt break selector chaining\", ->\n expect(textarea).toEqual $('#my-fixture')\n\n it \"loads previous stored value\", ->\n localStorage['unique-id'] = \"text\"\n textarea = $('#my-fixture-2').store 'unique-id'\n expect(textarea).toHaveValue \"text\"\n\n it \"updates the field on storage change\", ->\n localStorage['unique-id'] = \"text\"\n $(window).trigger \"storage\"\n expect(textarea).toHaveValue \"text\"\n\n it \"saves value to localStorage on input\", ->\n textarea.val \"foobar\"\n textarea.trigger 'input'\n expect(localStorage['unique-id']).toEqual \"foobar\"\n\n it \"wont (re)update the field on input\", ->\n spyOn storage, 'updateField'\n textarea.trigger 'input'\n expect(storage.updateField.calls.count()).toEqual 0\n\n it \"gets cleared on submit\", ->\n localStorage['unique-id'] = \"foo\"\n submitCallback = jasmine.createSpy('submitCallback').and.returnValue false\n $form = $('form')\n $form.on 'submit', submitCallback\n $form.trigger \"submit\"\n expect('unique-id' of localStorage).toBe false\n expect(submitCallback).toHaveBeenCalled()\n"]}
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
{"version":3,"sources":["util-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,mBAAT,EAA8B,SAAA;WAE1B,EAAA,CAAG,kBAAH,EAAuB,SAAA;AACnB,UAAA;MAAA,MAAA,GAAS,CAAC,CAAC,MAAF,CAAS,0BAAT,EAAqC;QAAC,GAAA,EAAK,UAAN;QAAkB,GAAA,EAAK,UAAvB;OAArC;aACT,MAAA,CAAO,MAAP,CAAc,CAAC,OAAf,CAAuB,gCAAvB;IAFmB,CAAvB;EAF0B,CAA9B;AAAA","file":"util-spec.js","sourceRoot":"/source/","sourcesContent":["describe \"util format tests\", ->\n\n it \"formats a string\", ->\n result = $.format \"{foo} foobar {bar} {bad}\", {foo: \"foo text\", bar: \"bar text\"}\n expect(result).toEqual \"foo text foobar bar text {bad}\"\n"]}
|
||||
{"version":3,"file":"util-spec.js","sources":["util-spec.coffee"],"names":[],"mappings":"AAAA;EAAA,QAAA,CAAS,mBAAT,EAA8B,SAAA;WAE1B,EAAA,CAAG,kBAAH,EAAuB,SAAA;AACnB,UAAA;MAAA,MAAA,GAAS,CAAC,CAAC,MAAF,CAAS,0BAAT,EAAqC;QAAC,GAAA,EAAK,UAAN;QAAkB,GAAA,EAAK,UAAvB;OAArC;aACT,MAAA,CAAO,MAAP,CAAc,CAAC,OAAf,CAAuB,gCAAvB;IAFmB,CAAvB;EAF0B,CAA9B;AAAA","sourcesContent":["describe \"util format tests\", ->\n\n it \"formats a string\", ->\n result = $.format \"{foo} foobar {bar} {bad}\", {foo: \"foo text\", bar: \"bar text\"}\n expect(result).toEqual \"foo text foobar bar text {bad}\"\n"]}
|
|
@ -0,0 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings as django_settings
|
||||
|
||||
from .registry import register
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def load_settings(context, *settings):
|
||||
context['st_settings'] = {
|
||||
setting: getattr(django_settings, setting)
|
||||
for setting in settings}
|
||||
return ''
|
|
@ -12,6 +12,7 @@ from ..tags import avatar
|
|||
from ..tags import gravatar
|
||||
from ..tags import messages
|
||||
from ..tags import paginator
|
||||
from ..tags import settings
|
||||
from ..tags import social_share
|
||||
from ..tags import time
|
||||
from ..tags import urls
|
||||
|
@ -30,6 +31,7 @@ __all__ = [
|
|||
'gravatar',
|
||||
'messages',
|
||||
'paginator',
|
||||
'settings',
|
||||
'social_share',
|
||||
'time',
|
||||
'urls',
|
||||
|
|
|
@ -33,15 +33,16 @@ ST_PRIVATE_FORUM = False
|
|||
# if that file contains a valid PNG header
|
||||
# followed by malicious HTML. See:
|
||||
# https://docs.djangoproject.com/en/1.11/topics/security/#user-uploaded-content
|
||||
ST_ALLOWED_UPLOAD_IMAGE_FORMAT = ('jpeg', 'gif')
|
||||
ST_ALLOWED_UPLOAD_IMAGE_FORMAT = ('jpeg', 'jpg', 'gif')
|
||||
ST_UPLOAD_IMAGE_ENABLED = True
|
||||
|
||||
# Only media types are allowed:
|
||||
# https://www.iana.org/assignments/media-types/media-types.xhtml
|
||||
ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE = OrderedDict([
|
||||
('doc', 'application/msword'), # .doc
|
||||
('docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'), # .docx
|
||||
('pdf', 'application/pdf'),
|
||||
])
|
||||
ST_ALLOWED_UPLOAD_FILE_MEDIA_TYPE = {
|
||||
'doc': 'application/msword',
|
||||
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'pdf': 'application/pdf'}
|
||||
ST_UPLOAD_FILE_ENABLED = True
|
||||
|
||||
ST_ALLOWED_URL_PROTOCOLS = {
|
||||
'http', 'https', 'mailto', 'ftp', 'ftps',
|
||||
|
|
Loading…
Reference in New Issue