spree_image_multi_upload 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/LICENSE +26 -0
- data/README.md +29 -0
- data/Rakefile +15 -0
- data/Versionfile +1 -0
- data/app/assets/javascripts/admin/jquery-fileupload/basic.js +4 -0
- data/app/assets/javascripts/admin/jquery-fileupload/cors/jquery.postmessage-transport.js +117 -0
- data/app/assets/javascripts/admin/jquery-fileupload/cors/jquery.xdr-transport.js +87 -0
- data/app/assets/javascripts/admin/jquery-fileupload/index.js +9 -0
- data/app/assets/javascripts/admin/jquery-fileupload/jquery.fileupload-fp.js +223 -0
- data/app/assets/javascripts/admin/jquery-fileupload/jquery.fileupload-ui.js +799 -0
- data/app/assets/javascripts/admin/jquery-fileupload/jquery.fileupload.js +1164 -0
- data/app/assets/javascripts/admin/jquery-fileupload/jquery.iframe-transport.js +185 -0
- data/app/assets/javascripts/admin/jquery-fileupload/locale.js.erb +30 -0
- data/app/assets/javascripts/admin/jquery-fileupload/vendor/canvas-to-blob.js +91 -0
- data/app/assets/javascripts/admin/jquery-fileupload/vendor/jquery.ui.widget.js +530 -0
- data/app/assets/javascripts/admin/jquery-fileupload/vendor/load-image.js +121 -0
- data/app/assets/javascripts/admin/jquery-fileupload/vendor/tmpl.js +86 -0
- data/app/assets/javascripts/admin/spree_image_multi_upload.js +3 -0
- data/app/assets/stylesheets/admin/jquery.fileupload-ui.scss +84 -0
- data/app/assets/stylesheets/admin/spree_image_multi_upload.css +4 -0
- data/app/controllers/spree/admin/images_controller_decorator.rb +39 -0
- data/app/models/image_decorator.rb +17 -0
- data/app/overrides/admin_decorator.rb +6 -0
- data/app/views/spree/admin/images/_template_download.html.erb +33 -0
- data/app/views/spree/admin/images/_template_upload.html.erb +36 -0
- data/app/views/spree/admin/images/multi_upload.html.erb +48 -0
- data/app/views/spree/admin/images/multi_upload.js.erb +4 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/ru.yml +15 -0
- data/config/routes.rb +11 -0
- data/lib/generators/spree_image_multi_upload/install/install_generator.rb +16 -0
- data/lib/spree_image_multi_upload.rb +2 -0
- data/lib/spree_image_multi_upload/engine.rb +22 -0
- data/script/rails +7 -0
- data/spec/spec_helper.rb +46 -0
- data/spree_image_multi_upload.gemspec +25 -0
- metadata +154 -0
@@ -0,0 +1,121 @@
|
|
1
|
+
/*
|
2
|
+
* JavaScript Load Image 1.2.1
|
3
|
+
* https://github.com/blueimp/JavaScript-Load-Image
|
4
|
+
*
|
5
|
+
* Copyright 2011, Sebastian Tschan
|
6
|
+
* https://blueimp.net
|
7
|
+
*
|
8
|
+
* Licensed under the MIT license:
|
9
|
+
* http://www.opensource.org/licenses/MIT
|
10
|
+
*/
|
11
|
+
|
12
|
+
/*jslint nomen: true */
|
13
|
+
/*global window, document, URL, webkitURL, Blob, File, FileReader, define */
|
14
|
+
|
15
|
+
(function ($) {
|
16
|
+
'use strict';
|
17
|
+
|
18
|
+
// Loads an image for a given File object.
|
19
|
+
// Invokes the callback with an img or optional canvas
|
20
|
+
// element (if supported by the browser) as parameter:
|
21
|
+
var loadImage = function (file, callback, options) {
|
22
|
+
var img = document.createElement('img'),
|
23
|
+
url,
|
24
|
+
oUrl;
|
25
|
+
img.onerror = callback;
|
26
|
+
img.onload = function () {
|
27
|
+
if (oUrl && !(options && options.noRevoke)) {
|
28
|
+
loadImage.revokeObjectURL(oUrl);
|
29
|
+
}
|
30
|
+
callback(loadImage.scale(img, options));
|
31
|
+
};
|
32
|
+
if ((window.Blob && file instanceof Blob) ||
|
33
|
+
// Files are also Blob instances, but some browsers
|
34
|
+
// (Firefox 3.6) support the File API but not Blobs:
|
35
|
+
(window.File && file instanceof File)) {
|
36
|
+
url = oUrl = loadImage.createObjectURL(file);
|
37
|
+
} else {
|
38
|
+
url = file;
|
39
|
+
}
|
40
|
+
if (url) {
|
41
|
+
img.src = url;
|
42
|
+
return img;
|
43
|
+
}
|
44
|
+
return loadImage.readFile(file, function (url) {
|
45
|
+
img.src = url;
|
46
|
+
});
|
47
|
+
},
|
48
|
+
// The check for URL.revokeObjectURL fixes an issue with Opera 12,
|
49
|
+
// which provides URL.createObjectURL but doesn't properly implement it:
|
50
|
+
urlAPI = (window.createObjectURL && window) ||
|
51
|
+
(window.URL && URL.revokeObjectURL && URL) ||
|
52
|
+
(window.webkitURL && webkitURL);
|
53
|
+
|
54
|
+
// Scales the given image (img or canvas HTML element)
|
55
|
+
// using the given options.
|
56
|
+
// Returns a canvas object if the browser supports canvas
|
57
|
+
// and the canvas option is true or a canvas object is passed
|
58
|
+
// as image, else the scaled image:
|
59
|
+
loadImage.scale = function (img, options) {
|
60
|
+
options = options || {};
|
61
|
+
var canvas = document.createElement('canvas'),
|
62
|
+
width = img.width,
|
63
|
+
height = img.height,
|
64
|
+
scale = Math.max(
|
65
|
+
(options.minWidth || width) / width,
|
66
|
+
(options.minHeight || height) / height
|
67
|
+
);
|
68
|
+
if (scale > 1) {
|
69
|
+
width = parseInt(width * scale, 10);
|
70
|
+
height = parseInt(height * scale, 10);
|
71
|
+
}
|
72
|
+
scale = Math.min(
|
73
|
+
(options.maxWidth || width) / width,
|
74
|
+
(options.maxHeight || height) / height
|
75
|
+
);
|
76
|
+
if (scale < 1) {
|
77
|
+
width = parseInt(width * scale, 10);
|
78
|
+
height = parseInt(height * scale, 10);
|
79
|
+
}
|
80
|
+
if (img.getContext || (options.canvas && canvas.getContext)) {
|
81
|
+
canvas.width = width;
|
82
|
+
canvas.height = height;
|
83
|
+
canvas.getContext('2d')
|
84
|
+
.drawImage(img, 0, 0, width, height);
|
85
|
+
return canvas;
|
86
|
+
}
|
87
|
+
img.width = width;
|
88
|
+
img.height = height;
|
89
|
+
return img;
|
90
|
+
};
|
91
|
+
|
92
|
+
loadImage.createObjectURL = function (file) {
|
93
|
+
return urlAPI ? urlAPI.createObjectURL(file) : false;
|
94
|
+
};
|
95
|
+
|
96
|
+
loadImage.revokeObjectURL = function (url) {
|
97
|
+
return urlAPI ? urlAPI.revokeObjectURL(url) : false;
|
98
|
+
};
|
99
|
+
|
100
|
+
// Loads a given File object via FileReader interface,
|
101
|
+
// invokes the callback with a data url:
|
102
|
+
loadImage.readFile = function (file, callback) {
|
103
|
+
if (window.FileReader && FileReader.prototype.readAsDataURL) {
|
104
|
+
var fileReader = new FileReader();
|
105
|
+
fileReader.onload = function (e) {
|
106
|
+
callback(e.target.result);
|
107
|
+
};
|
108
|
+
fileReader.readAsDataURL(file);
|
109
|
+
return fileReader;
|
110
|
+
}
|
111
|
+
return false;
|
112
|
+
};
|
113
|
+
|
114
|
+
if (typeof define === 'function' && define.amd) {
|
115
|
+
define(function () {
|
116
|
+
return loadImage;
|
117
|
+
});
|
118
|
+
} else {
|
119
|
+
$.loadImage = loadImage;
|
120
|
+
}
|
121
|
+
}(this));
|
@@ -0,0 +1,86 @@
|
|
1
|
+
/*
|
2
|
+
* JavaScript Templates 2.1.0
|
3
|
+
* https://github.com/blueimp/JavaScript-Templates
|
4
|
+
*
|
5
|
+
* Copyright 2011, Sebastian Tschan
|
6
|
+
* https://blueimp.net
|
7
|
+
*
|
8
|
+
* Licensed under the MIT license:
|
9
|
+
* http://www.opensource.org/licenses/MIT
|
10
|
+
*
|
11
|
+
* Inspired by John Resig's JavaScript Micro-Templating:
|
12
|
+
* http://ejohn.org/blog/javascript-micro-templating/
|
13
|
+
*/
|
14
|
+
|
15
|
+
/*jslint evil: true, regexp: true */
|
16
|
+
/*global document, define */
|
17
|
+
|
18
|
+
(function ($) {
|
19
|
+
"use strict";
|
20
|
+
var tmpl = function (str, data) {
|
21
|
+
var f = !/[^\w\-\.:]/.test(str) ? tmpl.cache[str] = tmpl.cache[str] ||
|
22
|
+
tmpl(tmpl.load(str)) :
|
23
|
+
new Function(
|
24
|
+
tmpl.arg + ',tmpl',
|
25
|
+
"var _e=tmpl.encode" + tmpl.helper + ",_s='" +
|
26
|
+
str.replace(tmpl.regexp, tmpl.func) +
|
27
|
+
"';return _s;"
|
28
|
+
);
|
29
|
+
return data ? f(data, tmpl) : function (data) {
|
30
|
+
return f(data, tmpl);
|
31
|
+
};
|
32
|
+
};
|
33
|
+
tmpl.cache = {};
|
34
|
+
tmpl.load = function (id) {
|
35
|
+
return document.getElementById(id).innerHTML;
|
36
|
+
};
|
37
|
+
tmpl.regexp = /([\s'\\])(?![^%]*%\})|(?:\{%(=|#)([\s\S]+?)%\})|(\{%)|(%\})/g;
|
38
|
+
tmpl.func = function (s, p1, p2, p3, p4, p5) {
|
39
|
+
if (p1) { // whitespace, quote and backspace in interpolation context
|
40
|
+
return {
|
41
|
+
"\n": "\\n",
|
42
|
+
"\r": "\\r",
|
43
|
+
"\t": "\\t",
|
44
|
+
" " : " "
|
45
|
+
}[s] || "\\" + s;
|
46
|
+
}
|
47
|
+
if (p2) { // interpolation: {%=prop%}, or unescaped: {%#prop%}
|
48
|
+
if (p2 === "=") {
|
49
|
+
return "'+_e(" + p3 + ")+'";
|
50
|
+
}
|
51
|
+
return "'+(" + p3 + "||'')+'";
|
52
|
+
}
|
53
|
+
if (p4) { // evaluation start tag: {%
|
54
|
+
return "';";
|
55
|
+
}
|
56
|
+
if (p5) { // evaluation end tag: %}
|
57
|
+
return "_s+='";
|
58
|
+
}
|
59
|
+
};
|
60
|
+
tmpl.encReg = /[<>&"'\x00]/g;
|
61
|
+
tmpl.encMap = {
|
62
|
+
"<" : "<",
|
63
|
+
">" : ">",
|
64
|
+
"&" : "&",
|
65
|
+
"\"" : """,
|
66
|
+
"'" : "'"
|
67
|
+
};
|
68
|
+
tmpl.encode = function (s) {
|
69
|
+
return String(s || "").replace(
|
70
|
+
tmpl.encReg,
|
71
|
+
function (c) {
|
72
|
+
return tmpl.encMap[c] || "";
|
73
|
+
}
|
74
|
+
);
|
75
|
+
};
|
76
|
+
tmpl.arg = "o";
|
77
|
+
tmpl.helper = ",print=function(s,e){_s+=e&&(s||'')||_e(s);}" +
|
78
|
+
",include=function(s,d){_s+=tmpl(s,d);}";
|
79
|
+
if (typeof define === "function" && define.amd) {
|
80
|
+
define(function () {
|
81
|
+
return tmpl;
|
82
|
+
});
|
83
|
+
} else {
|
84
|
+
$.tmpl = tmpl;
|
85
|
+
}
|
86
|
+
}(this));
|
@@ -0,0 +1,84 @@
|
|
1
|
+
@charset 'UTF-8';
|
2
|
+
/*
|
3
|
+
* jQuery File Upload UI Plugin CSS 6.3
|
4
|
+
* https://github.com/blueimp/jQuery-File-Upload
|
5
|
+
*
|
6
|
+
* Copyright 2010, Sebastian Tschan
|
7
|
+
* https://blueimp.net
|
8
|
+
*
|
9
|
+
* Licensed under the MIT license:
|
10
|
+
* http://www.opensource.org/licenses/MIT
|
11
|
+
*/
|
12
|
+
|
13
|
+
.fileinput-button {
|
14
|
+
position: relative;
|
15
|
+
overflow: hidden;
|
16
|
+
float: left;
|
17
|
+
margin-right: 4px;
|
18
|
+
}
|
19
|
+
.fileinput-button input {
|
20
|
+
position: absolute;
|
21
|
+
top: 0;
|
22
|
+
right: 0;
|
23
|
+
margin: 0;
|
24
|
+
border: solid transparent;
|
25
|
+
border-width: 0 0 100px 200px;
|
26
|
+
opacity: 0;
|
27
|
+
filter: alpha(opacity=0);
|
28
|
+
-moz-transform: translate(-300px, 0) scale(4);
|
29
|
+
direction: ltr;
|
30
|
+
cursor: pointer;
|
31
|
+
}
|
32
|
+
.fileupload-buttonbar .btn,
|
33
|
+
.fileupload-buttonbar .toggle {
|
34
|
+
margin-bottom: 5px;
|
35
|
+
}
|
36
|
+
.files .progress {
|
37
|
+
width: 200px;
|
38
|
+
}
|
39
|
+
.progress-animated .bar {
|
40
|
+
background: image-url('progressbar.gif') !important;
|
41
|
+
filter: none;
|
42
|
+
}
|
43
|
+
.fileupload-loading {
|
44
|
+
position: absolute;
|
45
|
+
left: 50%;
|
46
|
+
width: 128px;
|
47
|
+
height: 128px;
|
48
|
+
background: image-url('loading.gif') center no-repeat;
|
49
|
+
display: none;
|
50
|
+
}
|
51
|
+
.fileupload-processing .fileupload-loading {
|
52
|
+
display: block;
|
53
|
+
}
|
54
|
+
|
55
|
+
/* Fix for IE 6: */
|
56
|
+
* html .fileinput-button {
|
57
|
+
line-height: 22px;
|
58
|
+
margin: 1px -3px 0 0;
|
59
|
+
}
|
60
|
+
|
61
|
+
/* Fix for IE 7: */
|
62
|
+
* + html .fileinput-button {
|
63
|
+
margin: 1px 0 0 0;
|
64
|
+
}
|
65
|
+
|
66
|
+
@media (max-width: 480px) {
|
67
|
+
.files .btn span {
|
68
|
+
display: none;
|
69
|
+
}
|
70
|
+
.files .preview * {
|
71
|
+
width: 40px;
|
72
|
+
}
|
73
|
+
.files .name * {
|
74
|
+
width: 80px;
|
75
|
+
display: inline-block;
|
76
|
+
word-wrap: break-word;
|
77
|
+
}
|
78
|
+
.files .progress {
|
79
|
+
width: 20px;
|
80
|
+
}
|
81
|
+
.files .delete {
|
82
|
+
width: 60px;
|
83
|
+
}
|
84
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Spree::Admin::ImagesController.class_eval do
|
2
|
+
|
3
|
+
def create
|
4
|
+
|
5
|
+
product = Spree::Product.where('slug' => params['product_id'])
|
6
|
+
params[object_name][:attachment].each do |attachment_object|
|
7
|
+
#@object.attributes = params[object_name]
|
8
|
+
product = Spree::Product.where('slug' => params['product_id'])
|
9
|
+
#@object = Spree::Image.create
|
10
|
+
#@object.viewable.product = product
|
11
|
+
#@object.viewable_id = product[0].id
|
12
|
+
|
13
|
+
|
14
|
+
image = Spree::Image.new
|
15
|
+
image.attachment = attachment_object
|
16
|
+
image.viewable_id = params[:image][:viewable_id] #product[0].id
|
17
|
+
image.type = 'Spree::Image'
|
18
|
+
image.viewable_type = 'Spree::Variant'
|
19
|
+
#binding.pry
|
20
|
+
image.save
|
21
|
+
|
22
|
+
#invoke_callbacks(:create, :before)
|
23
|
+
#@object.attachment = attachment_object
|
24
|
+
#@object.save
|
25
|
+
#invoke_callbacks(:create, :after)
|
26
|
+
|
27
|
+
end
|
28
|
+
redirect_to '/admin/products/' + product[0].slug + '/images' #admin_product_url(product)
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def multi_upload
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def new_actions
|
37
|
+
[:new, :create, :multi_upload]
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Spree::Image.class_eval do
|
2
|
+
|
3
|
+
def to_jq_upload
|
4
|
+
{
|
5
|
+
'name' => read_attribute(:attachment_file_name),
|
6
|
+
'size' => read_attribute(:attachment_file_size),
|
7
|
+
'thumbnail_url' => attachment.url(:mini, false),
|
8
|
+
'url' => attachment.url(:product, false),
|
9
|
+
|
10
|
+
# TODO: find the way to generate edit and delete urls here
|
11
|
+
#include Rails.application.routes.url_helpers doesn't work
|
12
|
+
'edit_url' => '',
|
13
|
+
'delete_url' => ''
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
Deface::Override.new(
|
2
|
+
:virtual_path => 'spree/admin/images/index',
|
3
|
+
:replace => %q{code[erb-loud]:contains('t(:new_image)')},
|
4
|
+
:text => %q{<%= link_to_with_icon('icon-upload', t('multi_upload.title'), multi_upload_admin_product_images_path(@product), :id => 'multi_upload_images_link', :class => 'button', :remote => true) %>},
|
5
|
+
:name => 'add_images_multi_upload_button'
|
6
|
+
)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<script id="template-download" type="text/x-tmpl">
|
2
|
+
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
3
|
+
<tr class="template-download fade">
|
4
|
+
|
5
|
+
{% if (file.error) { %}
|
6
|
+
|
7
|
+
<td class="name"><span>{%=file.name%}</span></td>
|
8
|
+
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
|
9
|
+
<td class="error"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] ||
|
10
|
+
file.error%}
|
11
|
+
</td>
|
12
|
+
|
13
|
+
{% } else { %}
|
14
|
+
|
15
|
+
<td class="preview">{% if (file.thumbnail_url) { %}
|
16
|
+
<a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
|
17
|
+
{% } %}
|
18
|
+
</td>
|
19
|
+
<td class="name">
|
20
|
+
<a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}" download="{%=file.name%}">{%=file.name%}</a>
|
21
|
+
</td>
|
22
|
+
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
|
23
|
+
|
24
|
+
{% } %}
|
25
|
+
|
26
|
+
<td class="actions">
|
27
|
+
<a data-action="edit" class="icon_link with-tip icon-edit no-text" href="{%=file.edit_url%}" target="_blank"></a>
|
28
|
+
<a url="{%=file.delete_url%}" data-confirm="<%= t(:are_you_sure) %>" data-action="remove" class="delete-resource icon_link with-tip icon-trash no-text" href="{%=file.delete_url%}"></a>
|
29
|
+
</td>
|
30
|
+
|
31
|
+
</tr>
|
32
|
+
{% } %}
|
33
|
+
</script>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<script id="template-upload" type="text/x-tmpl">
|
2
|
+
{% for (var i=0, file; file=o.files[i]; i++) { %}
|
3
|
+
<tr class="template-upload fade">
|
4
|
+
<td class="preview"><span class="fade"></span></td>
|
5
|
+
<td class="name"><span>{%=file.name%}</span></td>
|
6
|
+
|
7
|
+
{% if (file.error) { %}
|
8
|
+
<td class="error">
|
9
|
+
<span class="label label-important"><%= t(:error) %></span>
|
10
|
+
{%=locale.fileupload.errors[file.error] || file.error%}
|
11
|
+
</td>
|
12
|
+
{% } else if (o.files.valid) { %}
|
13
|
+
<td class="size">
|
14
|
+
<span>{%=o.formatFileSize(file.size)%}</span>
|
15
|
+
</td>
|
16
|
+
{% } %}
|
17
|
+
|
18
|
+
<td class="actions">
|
19
|
+
|
20
|
+
{% if (!o.options.autoUpload) { %}
|
21
|
+
<span class="start">
|
22
|
+
<button class="button icon-upload">{%=locale.fileupload.start%}</button>
|
23
|
+
</span>
|
24
|
+
{% } %}
|
25
|
+
|
26
|
+
{% if (!i) { %}
|
27
|
+
<span class="cancel">
|
28
|
+
<button class="button icon-ban-circle">{%=locale.fileupload.cancel%}</button>
|
29
|
+
</span>
|
30
|
+
{% } %}
|
31
|
+
|
32
|
+
</td>
|
33
|
+
|
34
|
+
</tr>
|
35
|
+
{% } %}
|
36
|
+
</script>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<%= render :partial => 'spree/admin/shared/product_sub_menu' %>
|
2
|
+
<%= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Images' } %>
|
3
|
+
|
4
|
+
<%= render :partial => 'spree/shared/error_messages', :locals => {:target => @product} %>
|
5
|
+
|
6
|
+
<%= form_for [:admin, @product, @image], :html => {:multipart => true, :id => "fileupload", :method => :post} do |f| %>
|
7
|
+
<fieldset data-hook="new_product">
|
8
|
+
<legend align="center"><%= t('multi_upload.title') %></legend>
|
9
|
+
|
10
|
+
<div class="row fileupload-buttonbar">
|
11
|
+
<div data-hook="variant" class="field">
|
12
|
+
<%= f.label Spree::Variant.model_name.human %>
|
13
|
+
<br>
|
14
|
+
<%= f.select :viewable_id, @variants, {}, {:class => 'select2'} %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<span class="icon-plus button fileinput-button">
|
18
|
+
<%= t('multi_upload.add_files') %>
|
19
|
+
<%= f.file_field :attachment, {:multiple => true} %>
|
20
|
+
</span>
|
21
|
+
|
22
|
+
<button type="submit" class="icon-upload button start"><%= t('multi_upload.start') %></button>
|
23
|
+
<button type="reset" class="icon-ban-circle button cancel"><%= t('multi_upload.cancel') %></button>
|
24
|
+
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div class="fileupload-progress fade">
|
28
|
+
<div class="progress-extended"> </div>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<br />
|
32
|
+
|
33
|
+
<table role="presentation" class="table table-striped">
|
34
|
+
<tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery"></tbody>
|
35
|
+
</table>
|
36
|
+
|
37
|
+
</fieldset>
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
<script type="text/javascript" charset="utf-8">
|
41
|
+
$(function () {
|
42
|
+
$('#fileupload').fileupload();
|
43
|
+
});
|
44
|
+
</script>
|
45
|
+
|
46
|
+
<%= render :partial => 'template_upload' %>
|
47
|
+
<%= render :partial => 'template_download' %>
|
48
|
+
|