cas-cms 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +43 -0
- data/Rakefile +37 -0
- data/app/assets/config/cas_manifest.js +2 -0
- data/app/assets/images/cas/black-star.svg +4 -0
- data/app/assets/images/cas/check.svg +4 -0
- data/app/assets/images/cas/dropzone-in.svg +4 -0
- data/app/assets/images/cas/loading.gif +0 -0
- data/app/assets/images/cas/white-star.svg +4 -0
- data/app/assets/javascripts/cas/application.js +51 -0
- data/app/assets/javascripts/cas/fileupload_manifest.js +269 -0
- data/app/assets/javascripts/cas/plugins/cas_image_gallery.js +353 -0
- data/app/assets/javascripts/cas/vendor/file_upload/canvas-to-blob.min.js +2 -0
- data/app/assets/javascripts/cas/vendor/file_upload/jquery.fileupload-image.js +326 -0
- data/app/assets/javascripts/cas/vendor/file_upload/jquery.fileupload-process.js +178 -0
- data/app/assets/javascripts/cas/vendor/file_upload/jquery.fileupload.js +1482 -0
- data/app/assets/javascripts/cas/vendor/file_upload/jquery.iframe-transport.js +224 -0
- data/app/assets/javascripts/cas/vendor/file_upload/jquery.ui.widget.js +572 -0
- data/app/assets/javascripts/cas/vendor/file_upload/load-image.all.min.js +2 -0
- data/app/assets/javascripts/cas/vendor/jquery.ui.touch-punch.min.js +11 -0
- data/app/assets/javascripts/cas/vendor/selectize.min.js +3 -0
- data/app/assets/stylesheets/cas/application.sass +17 -0
- data/app/assets/stylesheets/cas/colors.sass +6 -0
- data/app/assets/stylesheets/cas/form.sass +99 -0
- data/app/assets/stylesheets/cas/layout.sass +68 -0
- data/app/assets/stylesheets/cas/mixins.sass +34 -0
- data/app/assets/stylesheets/cas/plugins/attachments_form.sass +16 -0
- data/app/assets/stylesheets/cas/plugins/image_gallery.sass +128 -0
- data/app/assets/stylesheets/cas/tables.sass +13 -0
- data/app/assets/stylesheets/cas/typography.sass +27 -0
- data/app/assets/stylesheets/cas/vendors/selectize.default.css +394 -0
- data/app/assets/stylesheets/cas/vendors/simplegrid.css +298 -0
- data/app/controllers/cas/api/files_controller.rb +88 -0
- data/app/controllers/cas/application_controller.rb +17 -0
- data/app/controllers/cas/devise/sessions_controller.rb +9 -0
- data/app/controllers/cas/file_uploads_controller.rb +14 -0
- data/app/controllers/cas/sections/application_controller.rb +23 -0
- data/app/controllers/cas/sections/categories_controller.rb +47 -0
- data/app/controllers/cas/sections/contents_controller.rb +144 -0
- data/app/controllers/cas/sections_controller.rb +7 -0
- data/app/controllers/cas/users_controller.rb +61 -0
- data/app/helpers/cas/application_helper.rb +4 -0
- data/app/helpers/cas/form_helper.rb +11 -0
- data/app/jobs/cas/application_job.rb +4 -0
- data/app/jobs/cas/images/delete_job.rb +11 -0
- data/app/jobs/cas/images/promote_job.rb +11 -0
- data/app/jobs/cas/increment_pageviews_job.rb +11 -0
- data/app/models/cas/application_record.rb +5 -0
- data/app/models/cas/category.rb +6 -0
- data/app/models/cas/content.rb +59 -0
- data/app/models/cas/media_file.rb +77 -0
- data/app/models/cas/section.rb +10 -0
- data/app/models/cas/site.rb +5 -0
- data/app/models/cas/user.rb +39 -0
- data/app/uploaders/file_uploader.rb +26 -0
- data/app/views/cas/devise/sessions/new.html.erb +24 -0
- data/app/views/cas/sections/categories/_form.html.erb +19 -0
- data/app/views/cas/sections/categories/edit.html.erb +5 -0
- data/app/views/cas/sections/categories/index.html.erb +28 -0
- data/app/views/cas/sections/categories/new.html.erb +5 -0
- data/app/views/cas/sections/contents/_form_attachments.html.erb +42 -0
- data/app/views/cas/sections/contents/_form_attachments_template.html.erb +11 -0
- data/app/views/cas/sections/contents/_form_for_content.html.erb +85 -0
- data/app/views/cas/sections/contents/_form_for_survey.html.erb +36 -0
- data/app/views/cas/sections/contents/_form_images.html.erb +86 -0
- data/app/views/cas/sections/contents/edit.html.erb +6 -0
- data/app/views/cas/sections/contents/index.html.erb +71 -0
- data/app/views/cas/sections/contents/new.html.erb +5 -0
- data/app/views/cas/sections/index.html.erb +21 -0
- data/app/views/cas/shared/_error_messages.html.erb +12 -0
- data/app/views/cas/users/_form.html.erb +11 -0
- data/app/views/cas/users/edit.html.erb +2 -0
- data/app/views/cas/users/index.html.erb +34 -0
- data/app/views/cas/users/new.html.erb +2 -0
- data/app/views/layouts/cas/application.html.erb +71 -0
- data/config/initializers/acts_as_taggable.rb +1 -0
- data/config/initializers/devise.rb +277 -0
- data/config/initializers/shrine.rb +50 -0
- data/config/initializers/simple_form.rb +169 -0
- data/config/locales/devise.en.yml +64 -0
- data/config/locales/pt-BR.yml +242 -0
- data/config/locales/simple_form.en.yml +31 -0
- data/config/routes.rb +31 -0
- data/db/migrate/20170129212144_create_cas_sites.rb +15 -0
- data/db/migrate/20170219172958_create_cas_sections.rb +12 -0
- data/db/migrate/20170219175007_create_cas_contents.rb +17 -0
- data/db/migrate/20170612204500_create_cas_users.rb +14 -0
- data/db/migrate/20170613174724_create_cas_media_files.rb +20 -0
- data/db/migrate/20170613175912_create_cas_categories.rb +14 -0
- data/db/migrate/20170614171928_add_columns_to_cas_contents.rb +12 -0
- data/db/migrate/20170614172904_add_column_to_cas_sections.rb +6 -0
- data/db/migrate/20170615235532_add_devise_to_cas_users.rb +49 -0
- data/db/migrate/20170616011202_remove_password_from_cas_users.rb +5 -0
- data/db/migrate/20170618014204_v3_migration_fields.rb +30 -0
- data/db/migrate/20170623182702_add_column_category_id_to_cas_content.rb +6 -0
- data/db/migrate/20170624024648_rename_url_to_path_in_files.rb +7 -0
- data/db/migrate/20170625192119_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb +36 -0
- data/db/migrate/20170625192120_add_missing_unique_indices.acts_as_taggable_on_engine.rb +26 -0
- data/db/migrate/20170625192121_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb +20 -0
- data/db/migrate/20170625192122_add_missing_taggable_index.acts_as_taggable_on_engine.rb +15 -0
- data/db/migrate/20170625192123_change_collation_for_tag_names.acts_as_taggable_on_engine.rb +15 -0
- data/db/migrate/20170625192124_add_missing_indexes_on_taggings.acts_as_taggable_on_engine.rb +23 -0
- data/db/migrate/20170713210101_add_location_to_cas_content.rb +5 -0
- data/db/migrate/20170714043036_add_url_to_content.rb +5 -0
- data/db/migrate/20170718201535_add_embedded_to_content.rb +5 -0
- data/db/migrate/20170801171952_categories_with_jsonb_metadata.rb +6 -0
- data/db/migrate/20170801173256_add_published_at_to_cas_contents.rb +6 -0
- data/db/migrate/20170801175407_add_description_to_cas_categories.rb +5 -0
- data/db/migrate/20170830000000_add_data_search_extensions.rb +17 -0
- data/db/migrate/20170830000001_add_search_index_to_cas_contents.rb +20 -0
- data/db/migrate/20170830000002_use_uuid_with_acts_as_taggable_references.rb +17 -0
- data/db/migrate/20170919181809_pageviews_default_to_zero.rb +9 -0
- data/db/migrate/20171201191059_add_domains_to_cas_site.rb +6 -0
- data/lib/cas.rb +22 -0
- data/lib/cas/config.rb +42 -0
- data/lib/cas/engine.rb +33 -0
- data/lib/cas/form_field.rb +54 -0
- data/lib/cas/remote_callbacks.rb +36 -0
- data/lib/cas/section_config.rb +84 -0
- data/lib/cas/setup.rb +43 -0
- data/lib/cas/version.rb +3 -0
- data/lib/devise/custom_failure.rb +16 -0
- data/lib/tasks/cas_tasks.rake +4 -0
- data/lib/templates/erb/scaffold/_form.html.erb +13 -0
- metadata +560 -0
@@ -0,0 +1,353 @@
|
|
1
|
+
/**
|
2
|
+
* Guess what, Javascript doesn't have .sort() by integer out-of-the-box.
|
3
|
+
*/
|
4
|
+
function sortNumber(a, b) {
|
5
|
+
return parseInt(a) - parseInt(b);
|
6
|
+
}
|
7
|
+
|
8
|
+
function CasImage(element, gallery) {
|
9
|
+
var image = this;
|
10
|
+
image.element = element;
|
11
|
+
image.gallery = gallery;
|
12
|
+
|
13
|
+
image.id = image.element.attr("data-id");
|
14
|
+
|
15
|
+
image.isSelected = function() {
|
16
|
+
return image.element.attr("data-selected") == "true";
|
17
|
+
};
|
18
|
+
|
19
|
+
image.markAsSelected = function() {
|
20
|
+
image.element.attr("data-selected", "true");
|
21
|
+
};
|
22
|
+
|
23
|
+
image.unselect = function() {
|
24
|
+
image.element.find(".selection").hide();
|
25
|
+
image.element.attr("data-selected", "false");
|
26
|
+
image.element.find(".unselected-but-selectable").show();
|
27
|
+
};
|
28
|
+
|
29
|
+
image.toggleSelection = function() {
|
30
|
+
if (image.isSelected()) {
|
31
|
+
image.unselect();
|
32
|
+
} else {
|
33
|
+
image.markAsSelected();
|
34
|
+
image.element.find(".unselected-but-selectable").hide();
|
35
|
+
image.element.find(".selection").show();
|
36
|
+
}
|
37
|
+
};
|
38
|
+
|
39
|
+
image.showEditOptions = function() {
|
40
|
+
gallery.element.find(".image .image-options").hide();
|
41
|
+
image.element.find(".image .image-options").show();
|
42
|
+
image.markAsSelected();
|
43
|
+
};
|
44
|
+
|
45
|
+
return {
|
46
|
+
click: function() {
|
47
|
+
if (image.gallery.isSelectionEnabled) {
|
48
|
+
image.toggleSelection();
|
49
|
+
} else {
|
50
|
+
image.showEditOptions();
|
51
|
+
}
|
52
|
+
},
|
53
|
+
unselect: function() {
|
54
|
+
if (image.isSelected()) {
|
55
|
+
image.unselect();
|
56
|
+
}
|
57
|
+
},
|
58
|
+
recordId: function() {
|
59
|
+
return image.element.data("id");
|
60
|
+
},
|
61
|
+
addOrderedInput: function(order) {
|
62
|
+
if (!image.element.find("input.js-image-input").length) {
|
63
|
+
image.element.append("<input type='hidden' name='images[files]["+order+"][id]' class='js-image-input' value='"+image.id+"' />");
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
function CasImageGallery(options) {
|
70
|
+
var gallery = this;
|
71
|
+
gallery.element = options.element;
|
72
|
+
|
73
|
+
gallery.isSelectionEnabled = options.selectionEnabled || false;
|
74
|
+
gallery.preloadedImagesSelector = options.preloadedImagesElements || gallery.element.find(".cas-gallery-preloaded");
|
75
|
+
|
76
|
+
gallery.allItems = function() {
|
77
|
+
return gallery.element.find(".image-container");
|
78
|
+
};
|
79
|
+
|
80
|
+
gallery.unselectAll = function() {
|
81
|
+
gallery.allItems().each(function(index) {
|
82
|
+
var image = new CasImage($(this), gallery);
|
83
|
+
image.unselect();
|
84
|
+
});
|
85
|
+
};
|
86
|
+
|
87
|
+
gallery.getSelectedItems = function() {
|
88
|
+
var result = [];
|
89
|
+
return gallery.element.find(".image-container[data-selected=true]").map(function(index, value) {
|
90
|
+
return $(value)
|
91
|
+
});
|
92
|
+
};
|
93
|
+
|
94
|
+
gallery.toggleSelection = function() {
|
95
|
+
gallery.isSelectionEnabled = !gallery.isSelectionEnabled;
|
96
|
+
|
97
|
+
if (!gallery.isSelectionEnabled) {
|
98
|
+
gallery.unselectAll();
|
99
|
+
} else {
|
100
|
+
gallery.unselectAll();
|
101
|
+
gallery.element.find(".unselected-but-selectable").show();
|
102
|
+
}
|
103
|
+
|
104
|
+
gallery.updateUi();
|
105
|
+
};
|
106
|
+
|
107
|
+
gallery.markAsCover = function(id) {
|
108
|
+
gallery.element.find(".image-container").attr("data-is-cover", "false");
|
109
|
+
gallery.element.find(".image-container[data-id="+id+"]").attr("data-is-cover", "true");
|
110
|
+
gallery.element.find("input.js-image-cover-input").remove();
|
111
|
+
gallery.element.append("<input type='hidden' name='images[cover_id]' class='js-image-cover-input' value='"+id+"' />");
|
112
|
+
};
|
113
|
+
|
114
|
+
gallery.deleteImages = function() {
|
115
|
+
var ids = [];
|
116
|
+
gallery.getSelectedItems().each(function(index, imageElement) {
|
117
|
+
var image = new CasImage(imageElement, gallery);
|
118
|
+
ids.push( String(image.recordId()) );
|
119
|
+
});
|
120
|
+
var response = options.onDelete(ids);
|
121
|
+
|
122
|
+
if (response) {
|
123
|
+
response.done(function() {
|
124
|
+
var imageSelectors = [];
|
125
|
+
$.each(ids, function(index, value) {
|
126
|
+
imageSelectors.push(".image-container[data-id="+value+"]");
|
127
|
+
});
|
128
|
+
gallery.element.find(imageSelectors.join(", ")).remove();
|
129
|
+
gallery.unselectAll();
|
130
|
+
if (gallery.isSelectionEnabled) {
|
131
|
+
gallery.toggleSelection();
|
132
|
+
}
|
133
|
+
}).fail(function() {
|
134
|
+
alert("Error!");
|
135
|
+
});
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
gallery.imageClicked = function(element) {
|
140
|
+
if (!gallery.isSelectionEnabled) {
|
141
|
+
gallery.unselectAll();
|
142
|
+
}
|
143
|
+
|
144
|
+
var image = new CasImage($(element), gallery);
|
145
|
+
image.click();
|
146
|
+
gallery.updateUi();
|
147
|
+
};
|
148
|
+
|
149
|
+
gallery.setupEvents = function() {
|
150
|
+
options.element.on("click", ".image-container", function() {
|
151
|
+
gallery.imageClicked($(this));
|
152
|
+
});
|
153
|
+
|
154
|
+
options.element.on("click", ".js-toggle-selection", function() {
|
155
|
+
gallery.toggleSelection();
|
156
|
+
});
|
157
|
+
|
158
|
+
options.element.on("click", ".js-delete-image", function() {
|
159
|
+
gallery.deleteImages();
|
160
|
+
});
|
161
|
+
|
162
|
+
options.element.on("click", ".js-mark-as-cover", function() {
|
163
|
+
var id = $(this).parents(".image-container").data("id");
|
164
|
+
gallery.markAsCover(id);
|
165
|
+
});
|
166
|
+
|
167
|
+
/*
|
168
|
+
* There's a bug with dragleave when over child elements, flickering. This
|
169
|
+
* fixes it.
|
170
|
+
*/
|
171
|
+
var dropzoneLastEnter;
|
172
|
+
$(document)
|
173
|
+
.on('dragover dragenter', ".dropzone", function(e) {
|
174
|
+
dropzoneLastEnter = event.target;
|
175
|
+
e.preventDefault();
|
176
|
+
|
177
|
+
var dataTransfer = e.originalEvent.dataTransfer;
|
178
|
+
if (dataTransfer.types && (dataTransfer.types.indexOf ? dataTransfer.types.indexOf('Files') != -1 : dataTransfer.types.contains('Files'))) {
|
179
|
+
$(this).addClass('in');
|
180
|
+
}
|
181
|
+
})
|
182
|
+
.on('dragleave drop', ".dropzone", function(e) {
|
183
|
+
if (dropzoneLastEnter === event.target) {
|
184
|
+
$(this).removeClass('in');
|
185
|
+
}
|
186
|
+
});
|
187
|
+
};
|
188
|
+
|
189
|
+
gallery.preloadImages = function() {
|
190
|
+
var images = gallery.preloadedImagesSelector;
|
191
|
+
|
192
|
+
$.each(images, function(index, value) {
|
193
|
+
var image = $(value);
|
194
|
+
var url = image.data("src");
|
195
|
+
var id = image.data("id");
|
196
|
+
var filename = image.data("filename");
|
197
|
+
var originalOrder = image.data("original-order");
|
198
|
+
var isCover = image.data("is-cover");
|
199
|
+
gallery.addImage({
|
200
|
+
url: url,
|
201
|
+
id: id,
|
202
|
+
filename: filename,
|
203
|
+
orderBy: "order",
|
204
|
+
originalOrder: originalOrder,
|
205
|
+
isCover: isCover
|
206
|
+
});
|
207
|
+
});
|
208
|
+
};
|
209
|
+
|
210
|
+
gallery.imageTemplate = $("#cas-gallery-image-template").html();
|
211
|
+
gallery.addImage = function(options) {
|
212
|
+
var url = options.url,
|
213
|
+
id = options.id,
|
214
|
+
filename = options.filename,
|
215
|
+
orderBy = options.orderBy,
|
216
|
+
// order that comes from the server
|
217
|
+
originalOrder = options.originalOrder,
|
218
|
+
isCover = options.isCover;
|
219
|
+
|
220
|
+
/**
|
221
|
+
* The new image information/HTML code
|
222
|
+
*/
|
223
|
+
var finalHtml = $(gallery.imageTemplate);
|
224
|
+
finalHtml.attr("data-id", id);
|
225
|
+
finalHtml.attr("data-filename", filename);
|
226
|
+
finalHtml.attr("data-original-order", originalOrder);
|
227
|
+
finalHtml.find(".image").css("backgroundImage", "url('"+url+"')");
|
228
|
+
|
229
|
+
/**
|
230
|
+
* We need to add images in order by filename. The sorting algorithm
|
231
|
+
* compares current image with the new image, and when the new image is
|
232
|
+
* going to be the last one, the algorithm in the loop below doesn't
|
233
|
+
* add it to the list of images.
|
234
|
+
*
|
235
|
+
* So we create `addedImage` to false. In case it's still false after the
|
236
|
+
* loop, we append the file to the end of the list.
|
237
|
+
*/
|
238
|
+
var addedImage = false;
|
239
|
+
gallery.allItems().each(function(index) {
|
240
|
+
if (addedImage === true) {
|
241
|
+
return false;
|
242
|
+
}
|
243
|
+
var ordering;
|
244
|
+
|
245
|
+
if (orderBy == "filename") {
|
246
|
+
var listedItemFilename = $(this).data("filename");
|
247
|
+
ordering = [listedItemFilename, filename].sort();
|
248
|
+
|
249
|
+
/**
|
250
|
+
* We compare the crrent file name and new file name. We sort them
|
251
|
+
* both.
|
252
|
+
*
|
253
|
+
* Say current images are 3.jpg and 6.jpg and new image is 5.jpg.
|
254
|
+
* We compare ["3.jpg", "5.jpg"].sort() and see that element zero is not
|
255
|
+
* 5.jpg. We discard it.
|
256
|
+
*
|
257
|
+
* Then ["6.jpg", "5.jpg"].sort() and "5.jpg" is the first element,
|
258
|
+
* therefore we surpassed the position 5.jpg should be in. At this
|
259
|
+
* point we take 5.jpg and `insertBefore()` 6.jpg.
|
260
|
+
*/
|
261
|
+
if (ordering[0] === filename) {
|
262
|
+
finalHtml.insertBefore($(this));
|
263
|
+
addedImage = true;
|
264
|
+
return;
|
265
|
+
}
|
266
|
+
} else if (orderBy == "order") {
|
267
|
+
var listedItemOrder = $(this).data("original-order");
|
268
|
+
ordering = [listedItemOrder, originalOrder].sort(sortNumber);
|
269
|
+
|
270
|
+
/**
|
271
|
+
* We compare the crrent file name and new file name. We sort them
|
272
|
+
* both.
|
273
|
+
*
|
274
|
+
* Say current images are 3.jpg and 6.jpg and new image is 5.jpg.
|
275
|
+
* We compare ["3.jpg", "5.jpg"].sort() and see that element zero is not
|
276
|
+
* 5.jpg. We discard it.
|
277
|
+
*
|
278
|
+
* Then ["6.jpg", "5.jpg"].sort() and "5.jpg" is the first element,
|
279
|
+
* therefore we surpassed the position 5.jpg should be in. At this
|
280
|
+
* point we take 5.jpg and `insertBefore()` 6.jpg.
|
281
|
+
*/
|
282
|
+
if (ordering[0] === originalOrder) {
|
283
|
+
finalHtml.insertBefore($(this));
|
284
|
+
addedImage = true;
|
285
|
+
return;
|
286
|
+
}
|
287
|
+
}
|
288
|
+
});
|
289
|
+
|
290
|
+
if (addedImage === false) {
|
291
|
+
gallery.element.find(".images").append(finalHtml);
|
292
|
+
}
|
293
|
+
|
294
|
+
gallery.refreshImagesFormInputs();
|
295
|
+
gallery.unselectAll();
|
296
|
+
|
297
|
+
if (isCover) {
|
298
|
+
gallery.markAsCover(id);
|
299
|
+
}
|
300
|
+
|
301
|
+
gallery.updateUi();
|
302
|
+
};
|
303
|
+
|
304
|
+
gallery.refreshImagesFormInputs = function() {
|
305
|
+
$(".js-image-input").remove();
|
306
|
+
gallery.allItems().each(function(index) {
|
307
|
+
var image = new CasImage($(this), gallery);
|
308
|
+
image.addOrderedInput(index);
|
309
|
+
});
|
310
|
+
};
|
311
|
+
|
312
|
+
gallery.updateUi = function() {
|
313
|
+
if (gallery.isSelectionEnabled) {
|
314
|
+
gallery.element.find(".when-selection-enabled").show();
|
315
|
+
gallery.element.find(".when-selection-disabled").hide();
|
316
|
+
gallery.element.find(".image .image-options").hide();
|
317
|
+
} else {
|
318
|
+
gallery.element.find(".unselected-but-selectable").hide();
|
319
|
+
gallery.element.find(".when-selection-enabled").hide();
|
320
|
+
gallery.element.find(".when-selection-disabled").show();
|
321
|
+
}
|
322
|
+
};
|
323
|
+
|
324
|
+
return {
|
325
|
+
init: function() {
|
326
|
+
gallery.preloadImages();
|
327
|
+
gallery.setupEvents();
|
328
|
+
gallery.updateUi();
|
329
|
+
},
|
330
|
+
|
331
|
+
addImage: function(options) {
|
332
|
+
gallery.addImage({
|
333
|
+
url: options.url,
|
334
|
+
id: options.id,
|
335
|
+
filename: options.filename,
|
336
|
+
orderBy: options.orderBy,
|
337
|
+
isCover: options.isCover
|
338
|
+
});
|
339
|
+
},
|
340
|
+
|
341
|
+
resetImagesOrder: function() {
|
342
|
+
gallery.element.find("input.js-image-input").remove();
|
343
|
+
gallery.refreshImagesFormInputs();
|
344
|
+
},
|
345
|
+
|
346
|
+
attachable: function() {
|
347
|
+
return {
|
348
|
+
type: gallery.element.data("attachable-type"),
|
349
|
+
id: gallery.element.data("attachable-id")
|
350
|
+
};
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
@@ -0,0 +1,2 @@
|
|
1
|
+
!function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,b,c,d,B,f;if(e=t.match(a),!e)throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),b=l?atob(u):decodeURIComponent(u),c=new ArrayBuffer(b.length),d=new Uint8Array(c),B=0;B<b.length;B+=1)d[B]=b.charCodeAt(B);return o?new Blob([n?d:c],{type:i}):(f=new r,f.append(c),f.getBlob(i))};t.HTMLCanvasElement&&!e.toBlob&&(e.mozGetAsFile?e.toBlob=function(t,o,n){t(n&&e.toDataURL&&i?i(this.toDataURL(o,n)):this.mozGetAsFile("blob",o))}:e.toDataURL&&i&&(e.toBlob=function(t,e,o){t(i(this.toDataURL(e,o)))})),"function"==typeof define&&define.amd?define(function(){return i}):"object"==typeof module&&module.exports?module.exports=i:t.dataURLtoBlob=i}(window);
|
2
|
+
//# sourceMappingURL=canvas-to-blob.min.js.map
|
@@ -0,0 +1,326 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery File Upload Image Preview & Resize Plugin
|
3
|
+
* https://github.com/blueimp/jQuery-File-Upload
|
4
|
+
*
|
5
|
+
* Copyright 2013, Sebastian Tschan
|
6
|
+
* https://blueimp.net
|
7
|
+
*
|
8
|
+
* Licensed under the MIT license:
|
9
|
+
* https://opensource.org/licenses/MIT
|
10
|
+
*/
|
11
|
+
|
12
|
+
/* jshint nomen:false */
|
13
|
+
/* global define, require, window, Blob */
|
14
|
+
|
15
|
+
;(function (factory) {
|
16
|
+
'use strict';
|
17
|
+
if (typeof define === 'function' && define.amd) {
|
18
|
+
// Register as an anonymous AMD module:
|
19
|
+
define([
|
20
|
+
'jquery',
|
21
|
+
'load-image',
|
22
|
+
'load-image-meta',
|
23
|
+
'load-image-scale',
|
24
|
+
'load-image-exif',
|
25
|
+
'canvas-to-blob',
|
26
|
+
'./jquery.fileupload-process'
|
27
|
+
], factory);
|
28
|
+
} else if (typeof exports === 'object') {
|
29
|
+
// Node/CommonJS:
|
30
|
+
factory(
|
31
|
+
require('jquery'),
|
32
|
+
require('blueimp-load-image/js/load-image'),
|
33
|
+
require('blueimp-load-image/js/load-image-meta'),
|
34
|
+
require('blueimp-load-image/js/load-image-scale'),
|
35
|
+
require('blueimp-load-image/js/load-image-exif'),
|
36
|
+
require('blueimp-canvas-to-blob'),
|
37
|
+
require('./jquery.fileupload-process')
|
38
|
+
);
|
39
|
+
} else {
|
40
|
+
// Browser globals:
|
41
|
+
factory(
|
42
|
+
window.jQuery,
|
43
|
+
window.loadImage
|
44
|
+
);
|
45
|
+
}
|
46
|
+
}(function ($, loadImage) {
|
47
|
+
'use strict';
|
48
|
+
|
49
|
+
// Prepend to the default processQueue:
|
50
|
+
$.blueimp.fileupload.prototype.options.processQueue.unshift(
|
51
|
+
{
|
52
|
+
action: 'loadImageMetaData',
|
53
|
+
disableImageHead: '@',
|
54
|
+
disableExif: '@',
|
55
|
+
disableExifThumbnail: '@',
|
56
|
+
disableExifSub: '@',
|
57
|
+
disableExifGps: '@',
|
58
|
+
disabled: '@disableImageMetaDataLoad'
|
59
|
+
},
|
60
|
+
{
|
61
|
+
action: 'loadImage',
|
62
|
+
// Use the action as prefix for the "@" options:
|
63
|
+
prefix: true,
|
64
|
+
fileTypes: '@',
|
65
|
+
maxFileSize: '@',
|
66
|
+
noRevoke: '@',
|
67
|
+
disabled: '@disableImageLoad'
|
68
|
+
},
|
69
|
+
{
|
70
|
+
action: 'resizeImage',
|
71
|
+
// Use "image" as prefix for the "@" options:
|
72
|
+
prefix: 'image',
|
73
|
+
maxWidth: '@',
|
74
|
+
maxHeight: '@',
|
75
|
+
minWidth: '@',
|
76
|
+
minHeight: '@',
|
77
|
+
crop: '@',
|
78
|
+
orientation: '@',
|
79
|
+
forceResize: '@',
|
80
|
+
disabled: '@disableImageResize'
|
81
|
+
},
|
82
|
+
{
|
83
|
+
action: 'saveImage',
|
84
|
+
quality: '@imageQuality',
|
85
|
+
type: '@imageType',
|
86
|
+
disabled: '@disableImageResize'
|
87
|
+
},
|
88
|
+
{
|
89
|
+
action: 'saveImageMetaData',
|
90
|
+
disabled: '@disableImageMetaDataSave'
|
91
|
+
},
|
92
|
+
{
|
93
|
+
action: 'resizeImage',
|
94
|
+
// Use "preview" as prefix for the "@" options:
|
95
|
+
prefix: 'preview',
|
96
|
+
maxWidth: '@',
|
97
|
+
maxHeight: '@',
|
98
|
+
minWidth: '@',
|
99
|
+
minHeight: '@',
|
100
|
+
crop: '@',
|
101
|
+
orientation: '@',
|
102
|
+
thumbnail: '@',
|
103
|
+
canvas: '@',
|
104
|
+
disabled: '@disableImagePreview'
|
105
|
+
},
|
106
|
+
{
|
107
|
+
action: 'setImage',
|
108
|
+
name: '@imagePreviewName',
|
109
|
+
disabled: '@disableImagePreview'
|
110
|
+
},
|
111
|
+
{
|
112
|
+
action: 'deleteImageReferences',
|
113
|
+
disabled: '@disableImageReferencesDeletion'
|
114
|
+
}
|
115
|
+
);
|
116
|
+
|
117
|
+
// The File Upload Resize plugin extends the fileupload widget
|
118
|
+
// with image resize functionality:
|
119
|
+
$.widget('blueimp.fileupload', $.blueimp.fileupload, {
|
120
|
+
|
121
|
+
options: {
|
122
|
+
// The regular expression for the types of images to load:
|
123
|
+
// matched against the file type:
|
124
|
+
loadImageFileTypes: /^image\/(gif|jpeg|png|svg\+xml)$/,
|
125
|
+
// The maximum file size of images to load:
|
126
|
+
loadImageMaxFileSize: 10000000, // 10MB
|
127
|
+
// The maximum width of resized images:
|
128
|
+
imageMaxWidth: 1920,
|
129
|
+
// The maximum height of resized images:
|
130
|
+
imageMaxHeight: 1080,
|
131
|
+
// Defines the image orientation (1-8) or takes the orientation
|
132
|
+
// value from Exif data if set to true:
|
133
|
+
imageOrientation: false,
|
134
|
+
// Define if resized images should be cropped or only scaled:
|
135
|
+
imageCrop: false,
|
136
|
+
// Disable the resize image functionality by default:
|
137
|
+
disableImageResize: true,
|
138
|
+
// The maximum width of the preview images:
|
139
|
+
previewMaxWidth: 80,
|
140
|
+
// The maximum height of the preview images:
|
141
|
+
previewMaxHeight: 80,
|
142
|
+
// Defines the preview orientation (1-8) or takes the orientation
|
143
|
+
// value from Exif data if set to true:
|
144
|
+
previewOrientation: true,
|
145
|
+
// Create the preview using the Exif data thumbnail:
|
146
|
+
previewThumbnail: true,
|
147
|
+
// Define if preview images should be cropped or only scaled:
|
148
|
+
previewCrop: false,
|
149
|
+
// Define if preview images should be resized as canvas elements:
|
150
|
+
previewCanvas: true
|
151
|
+
},
|
152
|
+
|
153
|
+
processActions: {
|
154
|
+
|
155
|
+
// Loads the image given via data.files and data.index
|
156
|
+
// as img element, if the browser supports the File API.
|
157
|
+
// Accepts the options fileTypes (regular expression)
|
158
|
+
// and maxFileSize (integer) to limit the files to load:
|
159
|
+
loadImage: function (data, options) {
|
160
|
+
if (options.disabled) {
|
161
|
+
return data;
|
162
|
+
}
|
163
|
+
var that = this,
|
164
|
+
file = data.files[data.index],
|
165
|
+
dfd = $.Deferred();
|
166
|
+
if (($.type(options.maxFileSize) === 'number' &&
|
167
|
+
file.size > options.maxFileSize) ||
|
168
|
+
(options.fileTypes &&
|
169
|
+
!options.fileTypes.test(file.type)) ||
|
170
|
+
!loadImage(
|
171
|
+
file,
|
172
|
+
function (img) {
|
173
|
+
if (img.src) {
|
174
|
+
data.img = img;
|
175
|
+
}
|
176
|
+
dfd.resolveWith(that, [data]);
|
177
|
+
},
|
178
|
+
options
|
179
|
+
)) {
|
180
|
+
return data;
|
181
|
+
}
|
182
|
+
return dfd.promise();
|
183
|
+
},
|
184
|
+
|
185
|
+
// Resizes the image given as data.canvas or data.img
|
186
|
+
// and updates data.canvas or data.img with the resized image.
|
187
|
+
// Also stores the resized image as preview property.
|
188
|
+
// Accepts the options maxWidth, maxHeight, minWidth,
|
189
|
+
// minHeight, canvas and crop:
|
190
|
+
resizeImage: function (data, options) {
|
191
|
+
if (options.disabled || !(data.canvas || data.img)) {
|
192
|
+
return data;
|
193
|
+
}
|
194
|
+
options = $.extend({canvas: true}, options);
|
195
|
+
var that = this,
|
196
|
+
dfd = $.Deferred(),
|
197
|
+
img = (options.canvas && data.canvas) || data.img,
|
198
|
+
resolve = function (newImg) {
|
199
|
+
if (newImg && (newImg.width !== img.width ||
|
200
|
+
newImg.height !== img.height ||
|
201
|
+
options.forceResize)) {
|
202
|
+
data[newImg.getContext ? 'canvas' : 'img'] = newImg;
|
203
|
+
}
|
204
|
+
data.preview = newImg;
|
205
|
+
dfd.resolveWith(that, [data]);
|
206
|
+
},
|
207
|
+
thumbnail;
|
208
|
+
if (data.exif) {
|
209
|
+
if (options.orientation === true) {
|
210
|
+
options.orientation = data.exif.get('Orientation');
|
211
|
+
}
|
212
|
+
if (options.thumbnail) {
|
213
|
+
thumbnail = data.exif.get('Thumbnail');
|
214
|
+
if (thumbnail) {
|
215
|
+
loadImage(thumbnail, resolve, options);
|
216
|
+
return dfd.promise();
|
217
|
+
}
|
218
|
+
}
|
219
|
+
// Prevent orienting the same image twice:
|
220
|
+
if (data.orientation) {
|
221
|
+
delete options.orientation;
|
222
|
+
} else {
|
223
|
+
data.orientation = options.orientation;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
if (img) {
|
227
|
+
resolve(loadImage.scale(img, options));
|
228
|
+
return dfd.promise();
|
229
|
+
}
|
230
|
+
return data;
|
231
|
+
},
|
232
|
+
|
233
|
+
// Saves the processed image given as data.canvas
|
234
|
+
// inplace at data.index of data.files:
|
235
|
+
saveImage: function (data, options) {
|
236
|
+
if (!data.canvas || options.disabled) {
|
237
|
+
return data;
|
238
|
+
}
|
239
|
+
var that = this,
|
240
|
+
file = data.files[data.index],
|
241
|
+
dfd = $.Deferred();
|
242
|
+
if (data.canvas.toBlob) {
|
243
|
+
data.canvas.toBlob(
|
244
|
+
function (blob) {
|
245
|
+
if (!blob.name) {
|
246
|
+
if (file.type === blob.type) {
|
247
|
+
blob.name = file.name;
|
248
|
+
} else if (file.name) {
|
249
|
+
blob.name = file.name.replace(
|
250
|
+
/\.\w+$/,
|
251
|
+
'.' + blob.type.substr(6)
|
252
|
+
);
|
253
|
+
}
|
254
|
+
}
|
255
|
+
// Don't restore invalid meta data:
|
256
|
+
if (file.type !== blob.type) {
|
257
|
+
delete data.imageHead;
|
258
|
+
}
|
259
|
+
// Store the created blob at the position
|
260
|
+
// of the original file in the files list:
|
261
|
+
data.files[data.index] = blob;
|
262
|
+
dfd.resolveWith(that, [data]);
|
263
|
+
},
|
264
|
+
options.type || file.type,
|
265
|
+
options.quality
|
266
|
+
);
|
267
|
+
} else {
|
268
|
+
return data;
|
269
|
+
}
|
270
|
+
return dfd.promise();
|
271
|
+
},
|
272
|
+
|
273
|
+
loadImageMetaData: function (data, options) {
|
274
|
+
if (options.disabled) {
|
275
|
+
return data;
|
276
|
+
}
|
277
|
+
var that = this,
|
278
|
+
dfd = $.Deferred();
|
279
|
+
loadImage.parseMetaData(data.files[data.index], function (result) {
|
280
|
+
$.extend(data, result);
|
281
|
+
dfd.resolveWith(that, [data]);
|
282
|
+
}, options);
|
283
|
+
return dfd.promise();
|
284
|
+
},
|
285
|
+
|
286
|
+
saveImageMetaData: function (data, options) {
|
287
|
+
if (!(data.imageHead && data.canvas &&
|
288
|
+
data.canvas.toBlob && !options.disabled)) {
|
289
|
+
return data;
|
290
|
+
}
|
291
|
+
var file = data.files[data.index],
|
292
|
+
blob = new Blob([
|
293
|
+
data.imageHead,
|
294
|
+
// Resized images always have a head size of 20 bytes,
|
295
|
+
// including the JPEG marker and a minimal JFIF header:
|
296
|
+
this._blobSlice.call(file, 20)
|
297
|
+
], {type: file.type});
|
298
|
+
blob.name = file.name;
|
299
|
+
data.files[data.index] = blob;
|
300
|
+
return data;
|
301
|
+
},
|
302
|
+
|
303
|
+
// Sets the resized version of the image as a property of the
|
304
|
+
// file object, must be called after "saveImage":
|
305
|
+
setImage: function (data, options) {
|
306
|
+
if (data.preview && !options.disabled) {
|
307
|
+
data.files[data.index][options.name || 'preview'] = data.preview;
|
308
|
+
}
|
309
|
+
return data;
|
310
|
+
},
|
311
|
+
|
312
|
+
deleteImageReferences: function (data, options) {
|
313
|
+
if (!options.disabled) {
|
314
|
+
delete data.img;
|
315
|
+
delete data.canvas;
|
316
|
+
delete data.preview;
|
317
|
+
delete data.imageHead;
|
318
|
+
}
|
319
|
+
return data;
|
320
|
+
}
|
321
|
+
|
322
|
+
}
|
323
|
+
|
324
|
+
});
|
325
|
+
|
326
|
+
}));
|