cone.fileupload 0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. cone/fileupload/__init__.py +34 -0
  2. cone/fileupload/browser/__init__.py +4 -0
  3. cone/fileupload/browser/actions.py +99 -0
  4. cone/fileupload/browser/fileupload.pt +54 -0
  5. cone/fileupload/browser/fileupload.py +185 -0
  6. cone/fileupload/browser/static/fileupload/jquery.fileupload-process.js +170 -0
  7. cone/fileupload/browser/static/fileupload/jquery.fileupload-ui.js +759 -0
  8. cone/fileupload/browser/static/fileupload/jquery.fileupload-validate.js +119 -0
  9. cone/fileupload/browser/static/fileupload/jquery.fileupload.css +36 -0
  10. cone/fileupload/browser/static/fileupload/jquery.fileupload.js +1604 -0
  11. cone/fileupload/browser/static/fileupload/jquery.iframe-transport.js +227 -0
  12. cone/fileupload/browser/static/fileupload/vendor/jquery.ui.widget.js +805 -0
  13. cone/fileupload/browser/static/fileupload/vendor/tmpl.min.js +1 -0
  14. cone/fileupload/browser/static/fileupload.css +21 -0
  15. cone/fileupload/browser/static/fileupload.js +69 -0
  16. cone/fileupload/browser/static/fileupload.min.js +1 -0
  17. cone/fileupload/browser/templates.py +103 -0
  18. cone/fileupload/browser/toolbar.pt +33 -0
  19. cone/fileupload/locale/cone.fileupload.pot +99 -0
  20. cone/fileupload/locale/de/LC_MESSAGES/cone.fileupload.mo +0 -0
  21. cone/fileupload/locale/de/LC_MESSAGES/cone.fileupload.po +98 -0
  22. cone/fileupload/tests.py +216 -0
  23. cone.fileupload-0.8-py3.9-nspkg.pth +1 -0
  24. cone_fileupload-0.8.dist-info/METADATA +291 -0
  25. cone_fileupload-0.8.dist-info/RECORD +29 -0
  26. cone_fileupload-0.8.dist-info/WHEEL +5 -0
  27. cone_fileupload-0.8.dist-info/licenses/LICENSE.rst +27 -0
  28. cone_fileupload-0.8.dist-info/namespace_packages.txt +1 -0
  29. cone_fileupload-0.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,34 @@
1
+ from cone.app import cfg
2
+ from cone.app import main_hook
3
+ from cone.fileupload.browser import static_resources
4
+ import logging
5
+
6
+
7
+ logger = logging.getLogger('cone.fileupload')
8
+
9
+
10
+ @main_hook
11
+ def initialize_fileupload(config, global_config, settings):
12
+ # application startup initialization
13
+
14
+ # protected CSS
15
+ cfg.css.protected.append('fileupload-static/fileupload/jquery.fileupload.css')
16
+ cfg.css.protected.append('fileupload-static/fileupload.css')
17
+
18
+ # protected JS
19
+ cfg.js.protected.append('fileupload-static/fileupload/vendor/tmpl.min.js')
20
+ cfg.js.protected.append('fileupload-static/fileupload/jquery.iframe-transport.js')
21
+ cfg.js.protected.append('fileupload-static/fileupload/jquery.fileupload.js')
22
+ cfg.js.protected.append('fileupload-static/fileupload/jquery.fileupload-process.js')
23
+ cfg.js.protected.append('fileupload-static/fileupload/jquery.fileupload-validate.js')
24
+ cfg.js.protected.append('fileupload-static/fileupload/jquery.fileupload-ui.js')
25
+ cfg.js.protected.append('fileupload-static/fileupload.js')
26
+
27
+ # add translation
28
+ config.add_translation_dirs('cone.fileupload:locale/')
29
+
30
+ # static resources
31
+ config.add_view(static_resources, name='fileupload-static')
32
+
33
+ # scan browser package
34
+ config.scan('cone.fileupload.browser')
@@ -0,0 +1,4 @@
1
+ from pyramid.static import static_view
2
+
3
+
4
+ static_resources = static_view('static', use_subpath=True)
@@ -0,0 +1,99 @@
1
+ from cone.app.browser.actions import Action
2
+ from cone.app.browser.actions import ButtonAction
3
+ from cone.app.browser.actions import LinkAction
4
+ from cone.app.browser.contextmenu import context_menu_item
5
+ from pyramid.i18n import get_localizer
6
+ from pyramid.i18n import TranslationStringFactory
7
+
8
+
9
+ _ = TranslationStringFactory('cone.fileupload')
10
+
11
+
12
+ @context_menu_item(group='childactions', name='add_files')
13
+ class ActionAddFiles(LinkAction):
14
+ id = 'toolbaraction-add-files'
15
+ icon = 'glyphicon glyphicon-plus'
16
+ text = _('action_add_files', default='Add files')
17
+ bind = None
18
+ target = None
19
+
20
+ @property
21
+ def display(self):
22
+ return (
23
+ self.model.properties.fileupload_contextmenu_actions
24
+ and self.permitted('add')
25
+ )
26
+
27
+
28
+ @context_menu_item(group='childactions', name='start_upload')
29
+ class ActionStartUpload(ButtonAction):
30
+ id = 'toolbaraction-start-upload'
31
+ icon = 'glyphicon glyphicon-upload'
32
+ text = _('action_start_upload', default='Start Upload')
33
+ css = 'start'
34
+ bind = None
35
+ target = None
36
+
37
+ @property
38
+ def display(self):
39
+ return (
40
+ self.model.properties.fileupload_contextmenu_actions
41
+ and self.permitted('add')
42
+ )
43
+
44
+
45
+ @context_menu_item(group='childactions', name='cancel_upload')
46
+ class ActionCancelUpload(ButtonAction):
47
+ id = 'toolbaraction-cancel-upload'
48
+ icon = 'glyphicon glyphicon-ban-circle'
49
+ text = _('action_cancel_upload', default='Cancel Upload')
50
+ css = 'cancel'
51
+ bind = None
52
+ target = None
53
+
54
+ @property
55
+ def display(self):
56
+ return (
57
+ self.model.properties.fileupload_contextmenu_actions
58
+ and self.permitted('add')
59
+ )
60
+
61
+
62
+ @context_menu_item(group='childactions', name='delete_files')
63
+ class ActionDeleteFiles(ButtonAction):
64
+ id = 'toolbaraction-delete-files'
65
+ icon = 'glyphicon glyphicon-trash'
66
+ text = _('action_delete_files', default='Delete Files')
67
+ css = 'delete'
68
+ bind = None
69
+ target = None
70
+
71
+ @property
72
+ def display(self):
73
+ return (
74
+ self.model.properties.fileupload_contextmenu_actions
75
+ and self.permitted('delete')
76
+ )
77
+
78
+
79
+ @context_menu_item(group='contextactions', name='select_files')
80
+ class ActionSelectFiles(Action):
81
+ id = 'toolbaraction-select-files'
82
+ text = _('action_select_files', default='Select Files')
83
+
84
+ @property
85
+ def display(self):
86
+ return (
87
+ self.model.properties.fileupload_contextmenu_actions
88
+ and self.permitted('delete')
89
+ )
90
+
91
+ def render(self):
92
+ localizer = get_localizer(self.request)
93
+ return (
94
+ u'<li class="select-files-action">'
95
+ u' <span>{}<input type="checkbox" class="toggle" /></span>'
96
+ u'</li>'
97
+ ).format(
98
+ localizer.translate(self.text)
99
+ )
@@ -0,0 +1,54 @@
1
+ <tal:block xmlns:tal="http://xml.zope.org/namespaces/tal"
2
+ xmlns:ajax="http://namespaces.conestack.org/ajax"
3
+ omit-tag="True">
4
+
5
+ <!-- The file upload form used as target for the file upload widget -->
6
+ <form id="fileupload"
7
+ data-url="${context.upload_url}"
8
+ data-accept_file_types="${context.accept_file_types}"
9
+ method="POST"
10
+ enctype="multipart/form-data">
11
+
12
+ <!-- The fileupload-buttonbar contains buttons to add/delete files and
13
+ start/cancel the upload -->
14
+ <div class="fileupload-buttonbar"
15
+ tal:define="show_contextmenu context.show_contextmenu">
16
+
17
+ <tal:contextmenu condition="show_contextmenu">
18
+ <tal:menu replace="structure tile('contextmenu')" />
19
+ <input type="file" name="files[]" multiple="multiple" style="display:none;"/>
20
+ </tal:contextmenu>
21
+
22
+ <tal:toolbar
23
+ condition="not show_contextmenu"
24
+ replace="structure tile('fileupload_toolbar')" />
25
+
26
+ </div>
27
+
28
+ <!-- The global progress state -->
29
+ <div class="fileupload-progress fade">
30
+
31
+ <!-- The global progress bar -->
32
+ <div class="progress progress-striped active col-md-6"
33
+ role="progressbar"
34
+ aria-valuemin="0"
35
+ aria-valuemax="100">
36
+ <div class="progress-bar progress-bar-success"
37
+ style="width:0%;"></div>
38
+ </div>
39
+
40
+ <!-- The extended global progress state -->
41
+ <div class="progress-extended col-md-6">&nbsp;</div>
42
+ </div>
43
+
44
+ <!-- The table listing the files available for upload/download -->
45
+ <table role="presentation" class="table table-striped">
46
+ <tbody class="files"></tbody>
47
+ </table>
48
+ </form>
49
+
50
+ <tal:i18n_messages replace="structure context.i18n_messages" />
51
+ <tal:upload_template replace="structure context.upload_template" />
52
+ <tal:download_template replace="structure context.download_template" />
53
+
54
+ </tal:block>
@@ -0,0 +1,185 @@
1
+ from cone.app.browser import render_main_template
2
+ from cone.app.browser.utils import make_url
3
+ from cone.fileupload.browser import templates
4
+ from cone.tile import Tile
5
+ from cone.tile import tile
6
+ from pyramid.i18n import get_localizer
7
+ from pyramid.i18n import TranslationStringFactory
8
+ from pyramid.view import view_config
9
+
10
+
11
+ _ = TranslationStringFactory('cone.fileupload')
12
+
13
+
14
+ @tile(
15
+ name='fileupload_toolbar',
16
+ path='toolbar.pt',
17
+ permission='add')
18
+ class FileUploadToolbarTile(Tile):
19
+ """Tile rendering the file upload toolbar.
20
+ """
21
+
22
+
23
+ @tile(name='fileupload', path='fileupload.pt', permission='add')
24
+ class FileUploadTile(Tile):
25
+ """Register this tile for specific context if jQuery file upload settings
26
+ should be customized.
27
+ """
28
+ accept_file_types = '' # e.g. /(\.|\/)(gif|jpe?g|png)$/i
29
+ i18n_messages_src = templates.I18N_MESSAGES
30
+ upload_template_src = templates.UPLOAD_TEMPLATE
31
+ download_template_src = templates.DOWNLOAD_TEMPLATE
32
+
33
+ @property
34
+ def show_contextmenu(self):
35
+ return self.model.properties.fileupload_contextmenu_actions
36
+
37
+ @property
38
+ def i18n_messages(self):
39
+ localizer = get_localizer(self.request)
40
+ translate = localizer.translate
41
+ return self.i18n_messages_src.format(
42
+ uploaded_bytes=translate(_(
43
+ 'uploaded_bytes',
44
+ default='Uploaded bytes exceed file size'
45
+ )),
46
+ accept_file_types=translate(_(
47
+ 'accept_file_types',
48
+ default='File type not allowed'
49
+ ))
50
+ )
51
+
52
+ @property
53
+ def upload_template(self):
54
+ localizer = get_localizer(self.request)
55
+ translate = localizer.translate
56
+ return self.upload_template_src.format(
57
+ processing=translate(_('processing', default=u'Processing...')),
58
+ start=translate(_('start', default=u'Start')),
59
+ cancel=translate(_('cancel', default=u'Cancel')),
60
+ )
61
+
62
+ @property
63
+ def download_template(self):
64
+ localizer = get_localizer(self.request)
65
+ translate = localizer.translate
66
+ return self.download_template_src.format(
67
+ error=translate(_('error', default=u'Error')),
68
+ delete=translate(_('delete', default=u'Delete')),
69
+ cancel=translate(_('cancel', default=u'Cancel')),
70
+ download=translate(_('download', default=u'Download')),
71
+ )
72
+
73
+ @property
74
+ def upload_url(self):
75
+ return make_url(
76
+ self.request,
77
+ node=self.model,
78
+ resource='fileupload_handle'
79
+ )
80
+
81
+
82
+ @view_config(name='fileupload', permission='add')
83
+ def fileupload(model, request):
84
+ """Fileupload as traversable view.
85
+ """
86
+ return render_main_template(model, request, 'fileupload')
87
+
88
+
89
+ # unknown mimetype marker
90
+ UNKNOWN_MIMETYPE = object()
91
+
92
+
93
+ @view_config(
94
+ name='fileupload_handle',
95
+ accept='application/json',
96
+ renderer='json',
97
+ permission='add')
98
+ class FileUploadHandle(object):
99
+ """Abstract file upload handle.
100
+
101
+ Subclass this object and register ``fileupload_handle`` tile for specific
102
+ context.
103
+
104
+ Methods ``read_existing`` and ``create_file`` are supposed to be
105
+ implemented on deriving object.
106
+ """
107
+
108
+ def __init__(self, model, request):
109
+ self.model = model
110
+ self.request = request
111
+
112
+ def __call__(self):
113
+ result = dict()
114
+ # initial reading
115
+ if self.request.method == 'GET':
116
+ result['files'] = self.read_existing()
117
+ # file upload
118
+ elif self.request.method == 'POST':
119
+ result['files'] = list()
120
+ for filedata in self.request.params.values():
121
+ mimetype = filedata.type or UNKNOWN_MIMETYPE
122
+ filename = filedata.filename
123
+ stream = filedata.file
124
+ res = self.create_file(stream, filename, mimetype)
125
+ result['files'].append(res)
126
+ return result
127
+
128
+ def read_existing(self):
129
+ """Read existing files in context and return a list of dicts containing
130
+ file data.
131
+
132
+ [
133
+ {
134
+ 'name': 'pic.jpg',
135
+ 'size': 841946,
136
+ 'view_url': 'http://example.org/pic.jpg',
137
+ 'download_url': 'http://example.org/pic.jpg/download',
138
+ 'delete_url': 'http://example.org/pic.jpg/filedelete_handle',
139
+ 'delete_type': 'GET',
140
+ }
141
+ ]
142
+ """
143
+ return []
144
+
145
+ def create_file(self, stream, filename, mimetype):
146
+ """Create file by uploaded stream and return file data dict.
147
+
148
+ {
149
+ 'name': 'pic.jpg',
150
+ 'size': 841946,
151
+ 'view_url': 'http://example.org/pic.jpg',
152
+ 'download_url': 'http://example.org/pic.jpg/download',
153
+ 'delete_url': 'http://example.org/pic.jpg/filedelete_handle',
154
+ 'delete_type': 'GET',
155
+ }
156
+ """
157
+ return {
158
+ 'name': filename,
159
+ 'size': 0,
160
+ 'error': (
161
+ 'Abstract ``FileUploadHandle`` does not '
162
+ 'implement ``create_file``'
163
+ )
164
+ }
165
+
166
+
167
+ @view_config(
168
+ name='filedelete_handle',
169
+ accept='application/json',
170
+ renderer='json',
171
+ permission='delete')
172
+ def filedelete_handle(model, request):
173
+ """Delete file and return client data.
174
+
175
+ {
176
+ 'files': [{
177
+ 'pic.jpg': True
178
+ }]
179
+ }
180
+ """
181
+ parent = model.parent
182
+ name = model.name
183
+ del parent[name]
184
+ parent()
185
+ return {'files': [{name: True}]}
@@ -0,0 +1,170 @@
1
+ /*
2
+ * jQuery File Upload Processing Plugin
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2012, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * https://opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* global define, require */
13
+
14
+ (function (factory) {
15
+ 'use strict';
16
+ if (typeof define === 'function' && define.amd) {
17
+ // Register as an anonymous AMD module:
18
+ define(['jquery', './jquery.fileupload'], factory);
19
+ } else if (typeof exports === 'object') {
20
+ // Node/CommonJS:
21
+ factory(require('jquery'), require('./jquery.fileupload'));
22
+ } else {
23
+ // Browser globals:
24
+ factory(window.jQuery);
25
+ }
26
+ })(function ($) {
27
+ 'use strict';
28
+
29
+ var originalAdd = $.blueimp.fileupload.prototype.options.add;
30
+
31
+ // The File Upload Processing plugin extends the fileupload widget
32
+ // with file processing functionality:
33
+ $.widget('blueimp.fileupload', $.blueimp.fileupload, {
34
+ options: {
35
+ // The list of processing actions:
36
+ processQueue: [
37
+ /*
38
+ {
39
+ action: 'log',
40
+ type: 'debug'
41
+ }
42
+ */
43
+ ],
44
+ add: function (e, data) {
45
+ var $this = $(this);
46
+ data.process(function () {
47
+ return $this.fileupload('process', data);
48
+ });
49
+ originalAdd.call(this, e, data);
50
+ }
51
+ },
52
+
53
+ processActions: {
54
+ /*
55
+ log: function (data, options) {
56
+ console[options.type](
57
+ 'Processing "' + data.files[data.index].name + '"'
58
+ );
59
+ }
60
+ */
61
+ },
62
+
63
+ _processFile: function (data, originalData) {
64
+ var that = this,
65
+ // eslint-disable-next-line new-cap
66
+ dfd = $.Deferred().resolveWith(that, [data]),
67
+ chain = dfd.promise();
68
+ this._trigger('process', null, data);
69
+ $.each(data.processQueue, function (i, settings) {
70
+ var func = function (data) {
71
+ if (originalData.errorThrown) {
72
+ // eslint-disable-next-line new-cap
73
+ return $.Deferred().rejectWith(that, [originalData]).promise();
74
+ }
75
+ return that.processActions[settings.action].call(
76
+ that,
77
+ data,
78
+ settings
79
+ );
80
+ };
81
+ chain = chain[that._promisePipe](func, settings.always && func);
82
+ });
83
+ chain
84
+ .done(function () {
85
+ that._trigger('processdone', null, data);
86
+ that._trigger('processalways', null, data);
87
+ })
88
+ .fail(function () {
89
+ that._trigger('processfail', null, data);
90
+ that._trigger('processalways', null, data);
91
+ });
92
+ return chain;
93
+ },
94
+
95
+ // Replaces the settings of each processQueue item that
96
+ // are strings starting with an "@", using the remaining
97
+ // substring as key for the option map,
98
+ // e.g. "@autoUpload" is replaced with options.autoUpload:
99
+ _transformProcessQueue: function (options) {
100
+ var processQueue = [];
101
+ $.each(options.processQueue, function () {
102
+ var settings = {},
103
+ action = this.action,
104
+ prefix = this.prefix === true ? action : this.prefix;
105
+ $.each(this, function (key, value) {
106
+ if ($.type(value) === 'string' && value.charAt(0) === '@') {
107
+ settings[key] =
108
+ options[
109
+ value.slice(1) ||
110
+ (prefix
111
+ ? prefix + key.charAt(0).toUpperCase() + key.slice(1)
112
+ : key)
113
+ ];
114
+ } else {
115
+ settings[key] = value;
116
+ }
117
+ });
118
+ processQueue.push(settings);
119
+ });
120
+ options.processQueue = processQueue;
121
+ },
122
+
123
+ // Returns the number of files currently in the processing queue:
124
+ processing: function () {
125
+ return this._processing;
126
+ },
127
+
128
+ // Processes the files given as files property of the data parameter,
129
+ // returns a Promise object that allows to bind callbacks:
130
+ process: function (data) {
131
+ var that = this,
132
+ options = $.extend({}, this.options, data);
133
+ if (options.processQueue && options.processQueue.length) {
134
+ this._transformProcessQueue(options);
135
+ if (this._processing === 0) {
136
+ this._trigger('processstart');
137
+ }
138
+ $.each(data.files, function (index) {
139
+ var opts = index ? $.extend({}, options) : options,
140
+ func = function () {
141
+ if (data.errorThrown) {
142
+ // eslint-disable-next-line new-cap
143
+ return $.Deferred().rejectWith(that, [data]).promise();
144
+ }
145
+ return that._processFile(opts, data);
146
+ };
147
+ opts.index = index;
148
+ that._processing += 1;
149
+ that._processingQueue = that._processingQueue[that._promisePipe](
150
+ func,
151
+ func
152
+ ).always(function () {
153
+ that._processing -= 1;
154
+ if (that._processing === 0) {
155
+ that._trigger('processstop');
156
+ }
157
+ });
158
+ });
159
+ }
160
+ return this._processingQueue;
161
+ },
162
+
163
+ _create: function () {
164
+ this._super();
165
+ this._processing = 0;
166
+ // eslint-disable-next-line new-cap
167
+ this._processingQueue = $.Deferred().resolveWith(this).promise();
168
+ }
169
+ });
170
+ });