alchemy-crop-image 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +289 -0
- data/MIT-LICENSE +20 -0
- data/README.md +37 -0
- data/Rakefile +32 -0
- data/alchemy-crop-image.gemspec +42 -0
- data/app/assets/config/alchemy_crop_image_manifest.js +2 -0
- data/app/assets/images/alchemy/crop/image/.keep +0 -0
- data/app/assets/javascripts/alchemy/crop/image/application.js +4 -0
- data/app/assets/javascripts/alchemy/crop/image/cropping.js +277 -0
- data/app/assets/javascripts/alchemy/crop/image/routes.js.erb +1 -0
- data/app/assets/stylesheets/alchemy/crop/image/application.scss +17 -0
- data/app/assets/stylesheets/alchemy/crop/image/cropping.scss +144 -0
- data/app/controllers/alchemy/admin/pictures/crops_controller.rb +46 -0
- data/app/helpers/alchemy/crop/image/application_helper.rb +8 -0
- data/app/jobs/alchemy/crop/image/application_job.rb +8 -0
- data/app/mailers/alchemy/crop/image/application_mailer.rb +10 -0
- data/app/views/alchemy/admin/pictures/_cropping.html.erb +93 -0
- data/app/views/alchemy/admin/pictures/show.html.erb +44 -0
- data/app/views/layouts/alchemy/crop/image/application.html.erb +15 -0
- data/bin/rails +14 -0
- data/config/initializers/assets.rb +1 -0
- data/config/locales/en.yml +30 -0
- data/config/locales/it.yml +30 -0
- data/config/routes.rb +13 -0
- data/lib/alchemy/crop/image/configuration.rb +23 -0
- data/lib/alchemy/crop/image/engine.rb +13 -0
- data/lib/alchemy/crop/image/version.rb +7 -0
- data/lib/alchemy/crop/image.rb +9 -0
- data/lib/generators/alchemy/crop/image/install_generator.rb +26 -0
- data/lib/tasks/alchemy/crop/image_tasks.rake +4 -0
- metadata +203 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
$(document).on("page:change turbolinks:load", function () {
|
2
|
+
|
3
|
+
var cropper = null;
|
4
|
+
var cropperData = null;
|
5
|
+
|
6
|
+
var enableCropperStructure = function () {
|
7
|
+
var imageContainer = $(".zoomed-picture-background")[0];
|
8
|
+
var picture = $(imageContainer).find("img")[0];
|
9
|
+
|
10
|
+
if (picture) {
|
11
|
+
|
12
|
+
//awful trick: disable click on background to prevent closing popup
|
13
|
+
$(".zoomed-picture-background").css("pointer-events", "none");
|
14
|
+
|
15
|
+
var middleBox = $(imageContainer).find(".middle-box-for-cropping")[0]
|
16
|
+
|
17
|
+
if (!middleBox) {
|
18
|
+
var box = "<div class='middle-box-for-cropping'><div class=\"cropperjs-container\"></div></div>"
|
19
|
+
$(imageContainer).append(box)
|
20
|
+
middleBox = $(box)
|
21
|
+
var cropperContainer = $(imageContainer).find(".cropperjs-container")
|
22
|
+
|
23
|
+
$(cropperContainer).append(picture)
|
24
|
+
|
25
|
+
|
26
|
+
}
|
27
|
+
|
28
|
+
//awful trick: enable click on cropping element and prevent propagation of click on it
|
29
|
+
middleBox = $(imageContainer).find(".middle-box-for-cropping")[0]
|
30
|
+
$(middleBox).css("pointer-events", "auto")
|
31
|
+
$(middleBox).click(function (e) {
|
32
|
+
e.stopPropagation();
|
33
|
+
e.preventDefault();
|
34
|
+
})
|
35
|
+
|
36
|
+
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
var onCrop = function (e) {
|
43
|
+
var roundedWidth = Math.round(e.detail.width)
|
44
|
+
var roundedHeight = Math.round(e.detail.height)
|
45
|
+
$("#field_width_crop").val(roundedWidth)
|
46
|
+
$("#field_height_crop").val(roundedHeight)
|
47
|
+
}
|
48
|
+
|
49
|
+
var enableCropperWithOptions = function (options) {
|
50
|
+
var imageContainer = $(".zoomed-picture-background")[0];
|
51
|
+
var picture = $(imageContainer).find("img")[0];
|
52
|
+
|
53
|
+
if (picture) {
|
54
|
+
// var cropperData = $(picture).data("cropperjs-data")
|
55
|
+
//
|
56
|
+
// if(cropperData) {
|
57
|
+
// options = $.extend(options,{
|
58
|
+
// autoCrop: true,
|
59
|
+
// data: cropperData
|
60
|
+
// });
|
61
|
+
// }
|
62
|
+
|
63
|
+
|
64
|
+
if (cropper) {
|
65
|
+
destroyCropper();
|
66
|
+
// var currentOptions = cropper.options
|
67
|
+
// var cropeprElement = cropper.element
|
68
|
+
// disableCropper()
|
69
|
+
// var newOptions = $.extend(currentOptions, options)
|
70
|
+
// cropper = new Cropper(cropeprElement, newOptions)
|
71
|
+
}
|
72
|
+
|
73
|
+
cropper = new Cropper(picture, options)
|
74
|
+
|
75
|
+
$(picture).unbind("crop").on("crop", onCrop)
|
76
|
+
|
77
|
+
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
}
|
82
|
+
|
83
|
+
var disableCropper = function () {
|
84
|
+
if (cropper) {
|
85
|
+
var picture = cropper.element
|
86
|
+
$(picture).data("cropperjs-data", cropper.getData())
|
87
|
+
cropper.destroy();
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
var destroyCropper = function () {
|
92
|
+
if (cropper) {
|
93
|
+
cropper.destroy();
|
94
|
+
cropper = null;
|
95
|
+
}
|
96
|
+
//awful trick: enable click on background to prevent closing popup
|
97
|
+
$(".zoomed-picture-background").css("pointer-events", "auto");
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
var showPanelCropping = function () {
|
102
|
+
$(".buttons-action-crop").show()
|
103
|
+
$(".crop-panel").show()
|
104
|
+
$("#enable-crop").hide()
|
105
|
+
}
|
106
|
+
|
107
|
+
var hidePanelCropping = function () {
|
108
|
+
$(".buttons-action-crop").hide()
|
109
|
+
$(".crop-panel").hide()
|
110
|
+
$("#enable-crop").show()
|
111
|
+
}
|
112
|
+
|
113
|
+
|
114
|
+
$(document).on("click", "#enable-crop", function () {
|
115
|
+
showPanelCropping();
|
116
|
+
enableCropperStructure();
|
117
|
+
enableCropperWithOptions(
|
118
|
+
{
|
119
|
+
dragMode: 'none',
|
120
|
+
modal: false,
|
121
|
+
rotatable: false,
|
122
|
+
scalable: false,
|
123
|
+
viewMode: 1,
|
124
|
+
autoCrop: true
|
125
|
+
}
|
126
|
+
);
|
127
|
+
|
128
|
+
// abilito il plugin del cropping
|
129
|
+
})
|
130
|
+
|
131
|
+
$(document).on("click", "#button-cancel-crop", function () {
|
132
|
+
hidePanelCropping();
|
133
|
+
destroyCropper();
|
134
|
+
//disabilito il plugin del cropping
|
135
|
+
})
|
136
|
+
|
137
|
+
$(document).on("click", "#button-save-crop", function () {
|
138
|
+
|
139
|
+
var imageContainer = $(".zoomed-picture-background")[0];
|
140
|
+
var originalPictureId = $(imageContainer).data("displayed-image-id");
|
141
|
+
|
142
|
+
if (cropper) {
|
143
|
+
|
144
|
+
//disable button for submit
|
145
|
+
$(this).prop("disabled", true)
|
146
|
+
$(this).attr("disabled", true)
|
147
|
+
|
148
|
+
var canvas = cropper.getCroppedCanvas();
|
149
|
+
if (canvas) {
|
150
|
+
canvas.toBlob(function (blob) {
|
151
|
+
var formData = new FormData();
|
152
|
+
var imgInfo = cropper.getCropBoxData()
|
153
|
+
|
154
|
+
formData.append('picture[image_file]', blob);
|
155
|
+
formData.append('image_info[width]', imgInfo.width);
|
156
|
+
formData.append('image_info[height]', imgInfo.height);
|
157
|
+
|
158
|
+
// Use `jQuery.ajax` method for example1
|
159
|
+
$.ajax(Routes.alchemy_admin_picture_crop_path(originalPictureId), {
|
160
|
+
method: 'POST',
|
161
|
+
data: formData,
|
162
|
+
processData: false,
|
163
|
+
contentType: false
|
164
|
+
});
|
165
|
+
});
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
})
|
170
|
+
|
171
|
+
$(document).on("click", "#drag-image", function () {
|
172
|
+
|
173
|
+
if (cropper) {
|
174
|
+
|
175
|
+
if ($(this).hasClass("active")) {
|
176
|
+
cropper.setDragMode("none")
|
177
|
+
$(this).removeClass("active")
|
178
|
+
} else {
|
179
|
+
cropper.setDragMode("move")
|
180
|
+
$(this).addClass("active")
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
// if($(this).hasClass("active")) {
|
185
|
+
// disableCropper()
|
186
|
+
// $(this).removeClass("active")
|
187
|
+
// } else {
|
188
|
+
// enableCropperWithOptions({
|
189
|
+
// dragMode: "move"
|
190
|
+
// })
|
191
|
+
// $(this).addClass("active")
|
192
|
+
// }
|
193
|
+
|
194
|
+
|
195
|
+
})
|
196
|
+
|
197
|
+
$(document).on("click", "#preview-image", function () {
|
198
|
+
if (cropper) {
|
199
|
+
|
200
|
+
if ($(this).hasClass("active-no-change")) {
|
201
|
+
|
202
|
+
var imageContainer = $(".zoomed-picture-background")[0];
|
203
|
+
var middlebox = $(imageContainer).find(".middle-box-for-cropping")[0];
|
204
|
+
var containerCropper = $(middlebox).find(".cropperjs-container")
|
205
|
+
var previewBox = $(middlebox).find(".preview-crop");
|
206
|
+
var buttonsActions = $(".crop-block .block-command .direct-action");
|
207
|
+
|
208
|
+
$(previewBox).remove();
|
209
|
+
$(containerCropper).show()
|
210
|
+
|
211
|
+
$(buttonsActions).prop("disabled", false);
|
212
|
+
$(buttonsActions).removeAttr("disabled");
|
213
|
+
|
214
|
+
|
215
|
+
$(this).removeClass("active-no-change")
|
216
|
+
$(this).html("<span class= \"fa fa-eye\"></span>")
|
217
|
+
} else {
|
218
|
+
|
219
|
+
var imageContainer = $(".zoomed-picture-background")[0];
|
220
|
+
var middlebox = $(imageContainer).find(".middle-box-for-cropping")[0];
|
221
|
+
var containerCropper = $(middlebox).find(".cropperjs-container");
|
222
|
+
var buttonsActions = $(".crop-block .block-command .direct-action");
|
223
|
+
$(containerCropper).css("display", "none");
|
224
|
+
|
225
|
+
var previewBox = $("<div class=\"preview-crop\"></div>");
|
226
|
+
|
227
|
+
var thisButton = this;
|
228
|
+
|
229
|
+
cropper.getCroppedCanvas().toBlob(function (blob) {
|
230
|
+
|
231
|
+
var urlCreator = window.URL || window.webkitURL;
|
232
|
+
var imageUrl = urlCreator.createObjectURL(blob);
|
233
|
+
$(previewBox).append("<img src='" + imageUrl + "'>");
|
234
|
+
$(middlebox).append(previewBox);
|
235
|
+
|
236
|
+
$(buttonsActions).prop("disabled", true);
|
237
|
+
$(buttonsActions).attr("disabled", true);
|
238
|
+
|
239
|
+
$(thisButton).addClass("active-no-change")
|
240
|
+
$(thisButton).html("<span class=\"fa fa-edit\"></span>")
|
241
|
+
});
|
242
|
+
|
243
|
+
|
244
|
+
}
|
245
|
+
|
246
|
+
|
247
|
+
}
|
248
|
+
})
|
249
|
+
|
250
|
+
$(document).on("click", "#crop-zoom-in", function () {
|
251
|
+
if (cropper) {
|
252
|
+
cropper.zoom(0.05)
|
253
|
+
}
|
254
|
+
})
|
255
|
+
|
256
|
+
$(document).on("click", "#crop-zoom-out", function () {
|
257
|
+
if (cropper) {
|
258
|
+
cropper.zoom(-0.05)
|
259
|
+
}
|
260
|
+
})
|
261
|
+
|
262
|
+
$(document).on("click", ".cropper-action-preset-ratio", function () {
|
263
|
+
if ($(this).hasClass("active")) {
|
264
|
+
$(this).removeClass("active");
|
265
|
+
} else {
|
266
|
+
$(".cropper-action-preset-ratio").removeClass("active");
|
267
|
+
var aspectRatioVal = $(this).data("value")
|
268
|
+
|
269
|
+
if (cropper) {
|
270
|
+
cropper.setAspectRatio(aspectRatioVal)
|
271
|
+
}
|
272
|
+
$(this).addClass("active");
|
273
|
+
}
|
274
|
+
})
|
275
|
+
|
276
|
+
|
277
|
+
})
|
@@ -0,0 +1 @@
|
|
1
|
+
Routes = <%= JsRoutes.generate() %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
* require_tree .
|
14
|
+
* require_self
|
15
|
+
*= require cropperjs/dist/cropper
|
16
|
+
*= require ./cropping
|
17
|
+
*/
|
@@ -0,0 +1,144 @@
|
|
1
|
+
|
2
|
+
@import "alchemy/variables";
|
3
|
+
$background_command: #214166;
|
4
|
+
$color_command: #ffffff;
|
5
|
+
|
6
|
+
|
7
|
+
.crop-block {
|
8
|
+
margin-top: 1rem;
|
9
|
+
|
10
|
+
#enable-crop, #button-save-crop{
|
11
|
+
background-color: $background_command;
|
12
|
+
color: $color_command;
|
13
|
+
}
|
14
|
+
|
15
|
+
|
16
|
+
.buttons-action-crop {
|
17
|
+
display: none;
|
18
|
+
}
|
19
|
+
|
20
|
+
.crop-panel {
|
21
|
+
display: none;
|
22
|
+
}
|
23
|
+
|
24
|
+
.block-command {
|
25
|
+
margin-top: 0.5rem;
|
26
|
+
|
27
|
+
.btn-group {
|
28
|
+
display: inline-block;
|
29
|
+
&.isolated{
|
30
|
+
margin-left: 15px;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
.cropper-action {
|
35
|
+
padding: 0.55em 1.5em;
|
36
|
+
&.active {
|
37
|
+
color: red
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
.block-info {
|
43
|
+
margin-top: 0.5rem;
|
44
|
+
|
45
|
+
.form-group {
|
46
|
+
margin-bottom: 0.5rem;
|
47
|
+
|
48
|
+
label {
|
49
|
+
display: inline-block;
|
50
|
+
margin-bottom: .5rem;
|
51
|
+
cursor: default;
|
52
|
+
}
|
53
|
+
|
54
|
+
.form-control {
|
55
|
+
display: block;
|
56
|
+
width: 100%;
|
57
|
+
padding: .375rem .75rem;
|
58
|
+
font-size: 1rem;
|
59
|
+
line-height: 1.5;
|
60
|
+
color: #495057;
|
61
|
+
background-color: #fff;
|
62
|
+
background-clip: padding-box;
|
63
|
+
border: 1px solid #ced4da;
|
64
|
+
border-radius: .25rem;
|
65
|
+
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
66
|
+
margin: auto;
|
67
|
+
}
|
68
|
+
|
69
|
+
.input-group {
|
70
|
+
position: relative;
|
71
|
+
display: -webkit-box;
|
72
|
+
display: -ms-flexbox;
|
73
|
+
display: flex;
|
74
|
+
flex-wrap: wrap;
|
75
|
+
align-items: stretch;
|
76
|
+
width: 100%;
|
77
|
+
|
78
|
+
.form-control {
|
79
|
+
position: relative;
|
80
|
+
flex: 1 1 auto;
|
81
|
+
width: 1%;
|
82
|
+
margin-bottom: 0;
|
83
|
+
}
|
84
|
+
|
85
|
+
.input-group-append {
|
86
|
+
margin-left: -1px;
|
87
|
+
display: flex;
|
88
|
+
|
89
|
+
.input-group-text {
|
90
|
+
display: flex;
|
91
|
+
-webkit-box-align: center;
|
92
|
+
-ms-flex-align: center;
|
93
|
+
align-items: center;
|
94
|
+
padding: .375rem .75rem;
|
95
|
+
margin-bottom: 0;
|
96
|
+
font-size: 1rem;
|
97
|
+
font-weight: 400;
|
98
|
+
line-height: 1.5;
|
99
|
+
color: #495057;
|
100
|
+
text-align: center;
|
101
|
+
white-space: nowrap;
|
102
|
+
background-color: #e9ecef;
|
103
|
+
border: 1px solid #ced4da;
|
104
|
+
border-radius: .25rem;
|
105
|
+
border-top-left-radius: 0;
|
106
|
+
border-bottom-left-radius: 0;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
.block-default-crop-size {
|
115
|
+
margin-top: 1rem;
|
116
|
+
|
117
|
+
.suggestion {
|
118
|
+
margin: 5px 0px;
|
119
|
+
}
|
120
|
+
|
121
|
+
.cropper-action-preset-ratio {
|
122
|
+
&.active {
|
123
|
+
color: red;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
|
129
|
+
.button_with_label {
|
130
|
+
margin: 0px;
|
131
|
+
}
|
132
|
+
|
133
|
+
}
|
134
|
+
|
135
|
+
.middle-box-for-cropping {
|
136
|
+
display: inline-block;
|
137
|
+
height: auto;
|
138
|
+
max-width: 100%;
|
139
|
+
max-height: 100%;
|
140
|
+
box-shadow: 0 0 8px rgba(51, 59, 81, 0.8);
|
141
|
+
background-color: #666666;
|
142
|
+
vertical-align: middle;
|
143
|
+
cursor: default;
|
144
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Alchemy
|
2
|
+
module Admin
|
3
|
+
module Pictures
|
4
|
+
class CropsController < Alchemy::Admin::BaseController
|
5
|
+
|
6
|
+
before_action :load_original_picture
|
7
|
+
|
8
|
+
|
9
|
+
def create
|
10
|
+
@picture = Picture.new(picture_params)
|
11
|
+
authorize! :create, @picture
|
12
|
+
if !params[:image_info].nil?
|
13
|
+
puts params[:image_info]
|
14
|
+
width = params[:image_info][:width]
|
15
|
+
height = params[:image_info][:height]
|
16
|
+
|
17
|
+
@picture.name = "#{@original_picture.name}_#{width}x#{height}"
|
18
|
+
else
|
19
|
+
@picture.name = "#{@original_picture.name}_#{SecureRandom.hex}"
|
20
|
+
end
|
21
|
+
@picture.image_file_name = @picture.name
|
22
|
+
@picture.tag_list = @original_picture.tag_list + ["#{width}x#{height}"]
|
23
|
+
if @picture.save
|
24
|
+
flash.notice = Alchemy.t(:cropped_image_succesfully_save, scope: :alchemy_crop_image)
|
25
|
+
redirect_to admin_pictures_path(filter: "last_upload")
|
26
|
+
else
|
27
|
+
flash[:error] = Alchemy.t(:cropped_image_not_saved, scope: :alchemy_crop_image)
|
28
|
+
redirect_to admin_pictures_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def load_original_picture
|
36
|
+
@original_picture = Alchemy::Picture.find params[:picture_id]
|
37
|
+
end
|
38
|
+
|
39
|
+
def picture_params
|
40
|
+
params.require(:picture).permit(:image_file)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<div class="crop-block">
|
2
|
+
<div class="block-button">
|
3
|
+
<button id="enable-crop">
|
4
|
+
<%= Alchemy.t(:enable_cropping, scope: :alchemy_crop_image) %>
|
5
|
+
</button>
|
6
|
+
<div class="buttons-action-crop">
|
7
|
+
<button id="button-cancel-crop">
|
8
|
+
<%= Alchemy.t(:cancel, scope: :alchemy_crop_image) %>
|
9
|
+
</button>
|
10
|
+
<button id="button-save-crop">
|
11
|
+
<%= Alchemy.t(:save_crop, scope: :alchemy_crop_image) %>
|
12
|
+
</button>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<div class="crop-panel">
|
16
|
+
<div class="block-command">
|
17
|
+
<div class="btn-group">
|
18
|
+
<button type="button" id="drag-image" class="cropper-action button_with_label direct-action">
|
19
|
+
<span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="<%= Alchemy.t(:move_image, scope: [:alchemy_crop_image, :cropping_actions]) %>">
|
20
|
+
<span class="fa fa-arrows-alt"></span>
|
21
|
+
</span>
|
22
|
+
<label><%= Alchemy.t(:label_drag_image, scope: [:alchemy_crop_image, :button_labels]) %></label>
|
23
|
+
|
24
|
+
</button>
|
25
|
+
<button id="crop-zoom-in" type="button" class="btn btn-primary button_with_label cropper-action direct-action">
|
26
|
+
<span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="">
|
27
|
+
<span class="fa fa-search-plus"></span>
|
28
|
+
</span>
|
29
|
+
<label><%= Alchemy.t(:label_zoom_in, scope: [:alchemy_crop_image, :button_labels]) %></label>
|
30
|
+
|
31
|
+
</button>
|
32
|
+
<button id="crop-zoom-out" type="button" class="btn btn-primary button_with_label cropper-action direct-action">
|
33
|
+
<span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="">
|
34
|
+
<span class="fa fa-search-minus"></span>
|
35
|
+
</span>
|
36
|
+
<label><%= Alchemy.t(:label_zoom_out, scope: [:alchemy_crop_image, :button_labels]) %></label>
|
37
|
+
</button>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
|
41
|
+
<div class="btn-group isolated">
|
42
|
+
<button type="button" id="preview-image" class="button_with_label cropper-action">
|
43
|
+
<span class="docs-tooltip" data-toggle="tooltip" title="" data-original-title="<%= Alchemy.t(:crop_image, scope: [:alchemy_crop_image, :cropping_actions]) %>">
|
44
|
+
<span class="fa fa-eye"></span>
|
45
|
+
</span>
|
46
|
+
<label><%= Alchemy.t(:label_preview_image, scope: [:alchemy_crop_image, :button_labels]) %></label>
|
47
|
+
</button>
|
48
|
+
</div>
|
49
|
+
|
50
|
+
|
51
|
+
</div>
|
52
|
+
<div class="block-info">
|
53
|
+
|
54
|
+
|
55
|
+
<div class="form-group">
|
56
|
+
<label><%= Alchemy.t(:width_crop, scope: :alchemy_crop_image) %></label>
|
57
|
+
<div class="input-group">
|
58
|
+
<input type="text" class="form-control" id="field_width_crop" readonly="true">
|
59
|
+
<div class="input-group-append">
|
60
|
+
<span class="input-group-text">px</span>
|
61
|
+
</div>
|
62
|
+
</div>
|
63
|
+
</div>
|
64
|
+
|
65
|
+
<div class="form-group">
|
66
|
+
<label><%= Alchemy.t(:height_crop, scope: :alchemy_crop_image) %></label>
|
67
|
+
<div class="input-group">
|
68
|
+
<input type="text" class="form-control" id="field_height_crop" readonly="true">
|
69
|
+
<div class="input-group-append">
|
70
|
+
<span class="input-group-text">px</span>
|
71
|
+
</div>
|
72
|
+
</div>
|
73
|
+
</div>
|
74
|
+
|
75
|
+
</div>
|
76
|
+
|
77
|
+
<div class="block-default-crop-size">
|
78
|
+
<div class="suggestion"><%= Alchemy.t(:you_can_select_a_preset_ratio_for_cropping, scope: :alchemy_crop_image) %></div>
|
79
|
+
<div class="btn-group">
|
80
|
+
<% Alchemy::Crop::Image::Configuration.available_preset_cropbox.each do |preset| %>
|
81
|
+
<button type="button" class="button_with_label cropper-action-preset-ratio" data-value="<%= preset[:value] %>">
|
82
|
+
<span class="label-ratio"><%= preset[:label] %></span>
|
83
|
+
<label><%= Alchemy.t(:label_crop_preset, scope: [:alchemy_crop_image, :button_labels], preset: preset[:label]) %></label>
|
84
|
+
</button>
|
85
|
+
<% end %>
|
86
|
+
<button type="button" class="button_with_label cropper-action-preset-ratio active" data-value="NaN">
|
87
|
+
<span class="label-ratio"><%= Alchemy.t(:preset_crop_ratio_none, scope: :alchemy_crop_image) %></span>
|
88
|
+
<label><%= Alchemy.t(:label_crop_preset_none, scope: [:alchemy_crop_image, :button_labels]) %></label>
|
89
|
+
</button>
|
90
|
+
</div>
|
91
|
+
</div>
|
92
|
+
</div>
|
93
|
+
</div>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<div class="zoomed-picture-background" data-displayed-image-id="<%= @picture.id %>">
|
2
|
+
<%= image_tag @picture.url(format: @picture.image_file_format) %>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div class="picture-overlay-navigation">
|
6
|
+
<% if @previous %>
|
7
|
+
<%= link_to alchemy.admin_picture_path(
|
8
|
+
id: @previous,
|
9
|
+
q: search_filter_params[:q],
|
10
|
+
page: params[:page],
|
11
|
+
tagged_with: search_filter_params[:tagged_with],
|
12
|
+
size: params[:size],
|
13
|
+
filter: search_filter_params[:filter]
|
14
|
+
),
|
15
|
+
class: "previous-picture",
|
16
|
+
remote: true do %>
|
17
|
+
<i class="icon fas fa-angle-left fa-fw"></i>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
<% if @next %>
|
21
|
+
<%= link_to alchemy.admin_picture_path(
|
22
|
+
id: @next,
|
23
|
+
q: search_filter_params[:q],
|
24
|
+
page: params[:page],
|
25
|
+
tagged_with: search_filter_params[:tagged_with],
|
26
|
+
size: params[:size],
|
27
|
+
filter: search_filter_params[:filter]
|
28
|
+
),
|
29
|
+
class: "next-picture",
|
30
|
+
remote: true do %>
|
31
|
+
<i class="icon fas fa-angle-right fa-fw"></i>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<div class="picture-details-overlay">
|
37
|
+
<%= render 'form' %>
|
38
|
+
<%= render 'infos' %>
|
39
|
+
<%= render partial: "cropping" %>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<div class="picture-overlay-handle">
|
43
|
+
<i class="icon fas fa-angle-double-right fa-fw"></i>
|
44
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Alchemy crop image</title>
|
5
|
+
<%= csrf_meta_tags %>
|
6
|
+
<%= csp_meta_tag %>
|
7
|
+
|
8
|
+
<%= stylesheet_link_tag "alchemy/crop/image/application", media: "all" %>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
|
12
|
+
<%= yield %>
|
13
|
+
|
14
|
+
</body>
|
15
|
+
</html>
|
data/bin/rails
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
3
|
+
# installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path('..', __dir__)
|
6
|
+
ENGINE_PATH = File.expand_path('../lib/alchemy/crop/image/engine', __dir__)
|
7
|
+
APP_PATH = File.expand_path('../test/dummy/config/application', __dir__)
|
8
|
+
|
9
|
+
# Set up gems listed in the Gemfile.
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
11
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
12
|
+
|
13
|
+
require 'rails/all'
|
14
|
+
require 'rails/engine/commands'
|
@@ -0,0 +1 @@
|
|
1
|
+
Alchemy::Crop::Image::Engine.config.assets.paths << Rails.root.join('node_modules')
|