refinerycms-images 4.0.3 → 4.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/refinery/admin/images_controller.rb +48 -9
  3. data/app/helpers/refinery/admin/images_helper.rb +12 -6
  4. data/app/models/refinery/image.rb +20 -12
  5. data/app/presenters/refinery/admin/grid_presenter.rb +42 -0
  6. data/app/presenters/refinery/admin/group_presenter.rb +68 -0
  7. data/app/presenters/refinery/admin/image_presenter.rb +145 -0
  8. data/app/presenters/refinery/admin/list_presenter.rb +23 -0
  9. data/app/views/refinery/admin/images/_crop.html.erb +7 -0
  10. data/app/views/refinery/admin/images/_existing_image.html.erb +52 -27
  11. data/app/views/refinery/admin/images/_form.html.erb +60 -12
  12. data/app/views/refinery/admin/images/_image.html.erb +5 -0
  13. data/app/views/refinery/admin/images/_list_view.html.erb +2 -2
  14. data/app/views/refinery/admin/images/destroy_crop.js.erb +18 -0
  15. data/config/locales/en.yml +11 -1
  16. data/config/locales/fr.yml +10 -0
  17. data/config/locales/sk.yml +17 -1
  18. data/config/routes.rb +6 -4
  19. data/db/migrate/20150430171341_translate_refinery_images.rb +13 -17
  20. data/db/migrate/20180711122352_add_parent_id_to_refinery_images.rb +5 -0
  21. data/lib/generators/refinery/images/templates/config/initializers/refinery/images.rb.erb +5 -2
  22. data/lib/refinery/images/configuration.rb +13 -7
  23. data/lib/refinery/images/validators/image_size_validator.rb +8 -8
  24. data/lib/refinery/images/validators/image_update_validator.rb +3 -3
  25. data/lib/refinery/images.rb +3 -3
  26. data/lib/refinerycms/images.rb +1 -0
  27. data/lib/refinerycms-images.rb +0 -1
  28. data/refinerycms-images.gemspec +13 -20
  29. data/spec/factories/image.rb +3 -3
  30. data/spec/support/shared_contexts/admin_images_tab.rb +1 -1
  31. data/spec/support/shared_contexts/grid_view.rb +8 -0
  32. data/spec/support/shared_contexts/list_view.rb +12 -0
  33. data/spec/support/shared_examples/image_deleter.rb +1 -1
  34. data/spec/support/shared_examples/image_previewer.rb +1 -1
  35. data/spec/support/shared_examples/image_translator.rb +1 -1
  36. data/spec/support/shared_examples/image_uploader.rb +6 -3
  37. data/spec/{features → system}/refinery/admin/dialog_spec.rb +1 -1
  38. data/spec/{features → system}/refinery/admin/images_spec.rb +13 -1
  39. metadata +31 -87
  40. checksums.yaml.gz.sig +0 -0
  41. data.tar.gz.sig +0 -0
  42. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ace9c6f436bf1a41d2025a7930a950eb0e6b68b2726498b6dce7abcfe033e5a4
4
- data.tar.gz: d42c450cd1c5c3abd85fce72743e571e129868625070e9413431a040820469bd
3
+ metadata.gz: 9843f043fac07905d1893351f1f570530acb3e5864bfb33340f8a8144cf83d4f
4
+ data.tar.gz: 10dbda158cc2298e77cf3b5340a32a0b238093dec5b4be4a493576caf2d022e4
5
5
  SHA512:
6
- metadata.gz: 706080c62145f80e477671d3f6ca6b6d6e1c689214f4eea2b8143444b9da5532d005d5f6f0c5921a3f116ff2fded37d6f19d900de2fbc779ea75a73286123da7
7
- data.tar.gz: 93243ec3b8edf6f3a265108e5a404fa2eb83113171246cbcfba3d5c97f2452f88569f21f91189d125399116b3e485a3db1a7985b8e0d580ac4f7811259e01483
6
+ metadata.gz: baf1f003fc65d7deb38c1ce79b2559d8b6955aa9755fe7f87360bad8a7dfea512bb9dc286ff1aaaba8732b2c7af11c59da902787292fb9259bb9163c723dadc4
7
+ data.tar.gz: d0ca50f9d0333d4dd8fb22d43294e948f660cc40d00114d4d995478d7d195390d50e907da36cc2d3d8870a5c2cb2348833d41ac9724ac373922daeb3a0f7fe34
@@ -1,11 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'will_paginate/array'
4
+
1
5
  module Refinery
2
6
  module Admin
3
7
  class ImagesController < ::Refinery::AdminController
4
8
 
5
9
  crudify :'refinery/image',
6
- include: [:translations],
10
+ include: [:translations, :crops],
7
11
  order: "updated_at DESC",
8
- sortable: false
12
+ sortable: false,
13
+ conditions: 'parent_id IS NULL',
14
+ find_actions: [:update, :destroy, :edit]
9
15
 
10
16
  before_action :change_list_mode_if_specified, :init_dialog
11
17
 
@@ -18,7 +24,6 @@ module Refinery
18
24
  # This renders the image insert dialog
19
25
  def insert
20
26
  self.new if @image.nil?
21
-
22
27
  @url_override = refinery.admin_images_path(request.query_parameters.merge(insert: true))
23
28
 
24
29
  if params[:conditions].present?
@@ -42,8 +47,10 @@ module Refinery
42
47
  begin
43
48
  if params[:image].present? && params[:image][:image].is_a?(Array)
44
49
  params[:image][:image].each do |image|
45
- params[:image][:image_title] = params[:image][:image_title].presence || auto_title(image.original_filename)
46
- @images << (@image = ::Refinery::Image.create({image: image}.merge(image_params.except(:image).to_h)))
50
+ image_title = params[:image][:image_title].presence || auto_title(image.original_filename)
51
+ @images << @image = ::Refinery::Image.create(
52
+ image_params.merge(image_title: image_title, image: image)
53
+ )
47
54
  end
48
55
  else
49
56
  @images << (@image = ::Refinery::Image.create(image_params))
@@ -91,7 +98,7 @@ module Refinery
91
98
  if request.xhr?
92
99
  render partial: '/refinery/message'
93
100
  else
94
- redirect_to :back
101
+ redirect_back(fallback_location: { action: 'edit' })
95
102
  end
96
103
  else
97
104
  redirect_back_or_default refinery.admin_images_path
@@ -110,6 +117,39 @@ module Refinery
110
117
  end
111
118
  end
112
119
 
120
+ def crop
121
+ parent_image = ::Refinery::Image.find_by_id(params[:image_id])
122
+
123
+ cropped_image = ::Refinery::Image.new(
124
+ parent_id: parent_image.id,
125
+ image: params[:image]
126
+ )
127
+
128
+ if cropped_image.valid? && cropped_image.save!
129
+ flash.notice = ::I18n.t('refinery.admin.images.form.crop_success')
130
+ render json: {
131
+ message: ::I18n.t('refinery.admin.images.form.crop_success'),
132
+ crop: render_to_string('/refinery/admin/images/_crop', layout: false, locals: { crop: cropped_image})
133
+ }
134
+ else
135
+ flash.now[:error] = ::I18n.t('refinery.admin.images.form.crop_error')
136
+ render json: { message: ::I18n.t('refinery.admin.images.form.crop_error') }
137
+ end
138
+ end
139
+
140
+ def destroy_crop
141
+ @image = Refinery::Image.find_by_id(params[:image_id])
142
+ title = @image.parent.image_name
143
+
144
+ if @image.destroy
145
+ flash.notice = t('destroyed', scope: 'refinery.crudify', what: title)
146
+
147
+ respond_to do |format|
148
+ format.js { render "/refinery/admin/images/destroy_crop", locals: { image_id: @image.id } }
149
+ end
150
+ end
151
+ end
152
+
113
153
  protected
114
154
 
115
155
  def init_dialog
@@ -130,7 +170,7 @@ module Refinery
130
170
  end
131
171
 
132
172
  def paginate_images
133
- @images = @images.paginate(page: params[:page], per_page: Image.per_page(from_dialog?, !@app_dialog))
173
+ @images = @images.root.paginate(page: params[:page], per_page: Image.per_page(from_dialog?, !@app_dialog))
134
174
  end
135
175
 
136
176
  def restrict_controller
@@ -149,10 +189,9 @@ module Refinery
149
189
 
150
190
  def permitted_image_params
151
191
  [
152
- :image, :image_size, :image_title, :image_alt
192
+ { image: [] }, :image_size, :image_title, :image_alt
153
193
  ]
154
194
  end
155
-
156
195
  end
157
196
  end
158
197
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Refinery
2
4
  module Admin
3
5
  module ImagesHelper
@@ -7,17 +9,21 @@ module Refinery
7
9
  end
8
10
  end
9
11
 
12
+ def locale_text_icon(text)
13
+ text
14
+ end
15
+
10
16
  def thumbnail_urls(image)
11
- thumbnail_urls = {
12
- :"data-original" => image_path(image.url),
13
- :"data-grid" => image_path(image.thumbnail(:geometry => '135x135#c').url)
17
+ thumbnails = {
18
+ original: image_path(image.url),
19
+ grid: image_path(image.thumbnail(geometry: '135x135#c').url)
14
20
  }
15
21
 
16
- Refinery::Images.user_image_sizes.sort_by{ |key, geometry| geometry}.each do |size, pixels|
17
- thumbnail_urls[:"data-#{size.to_s.parameterize}"] = image_path(image.thumbnail(:geometry => pixels).url)
22
+ Refinery::Images.user_image_sizes.sort_by { |key, geometry| geometry }.each do |size, pixels|
23
+ thumbnails[size.to_s.parameterize] = image_path(image.thumbnail(geometry: pixels).url)
18
24
  end
19
25
 
20
- thumbnail_urls
26
+ { data: thumbnails }
21
27
  end
22
28
  end
23
29
  end
@@ -2,24 +2,32 @@ require 'dragonfly'
2
2
 
3
3
  module Refinery
4
4
  class Image < Refinery::Core::BaseModel
5
+ extend Mobility
5
6
  translates :image_title, :image_alt
6
7
 
7
- attribute :image_title
8
- attribute :image_alt
9
-
10
- dragonfly_accessor :image, :app => :refinery_images
8
+ dragonfly_accessor :image, app: :refinery_images
11
9
 
12
10
  include Images::Validators
13
11
 
14
- validates :image, :presence => true
12
+ validates :image, presence: true
15
13
  validates_with ImageSizeValidator
16
- validates_with ImageUpdateValidator, :on => :update
14
+ validates_with ImageUpdateValidator, on: :update
17
15
  validates_property :mime_type,
18
- :of => :image,
19
- :in => ::Refinery::Images.whitelisted_mime_types,
20
- :message => :incorrect_format
16
+ of: :image,
17
+ in: ::Refinery::Images.allowed_mime_types,
18
+ message: ->(mime_type, image){
19
+ ::I18n.t(:incorrect_format,
20
+ scope: 'activerecord.errors.models.refinery/image',
21
+ actual: mime_type,
22
+ valid_types: ::Refinery::Images.allowed_mime_types_msg)
23
+ }
24
+
25
+ delegate :size, :mime_type, :url, :width, :height, to: :image
26
+
27
+ has_many :crops, class_name: '::Refinery::Image', foreign_key: 'parent_id', dependent: :destroy
28
+ belongs_to :parent, class_name: '::Refinery::Image', foreign_key: 'parent_id', optional: true
21
29
 
22
- delegate :size, :mime_type, :url, :width, :height, :to => :image
30
+ scope :root, -> { where(parent_id: nil) }
23
31
 
24
32
  class << self
25
33
  # How many images per page should be displayed?
@@ -38,7 +46,7 @@ module Refinery
38
46
 
39
47
  # Get a thumbnail job object given a geometry and whether to strip image profiles and comments.
40
48
  def thumbnail(options = {})
41
- options = { :geometry => nil, :strip => false }.merge(options)
49
+ options = { geometry: nil, strip: false }.merge(options)
42
50
  geometry = convert_to_geometry(options[:geometry])
43
51
  thumbnail = image
44
52
  thumbnail = thumbnail.thumb(geometry) if geometry
@@ -49,7 +57,7 @@ module Refinery
49
57
  # Intelligently works out dimensions for a thumbnail of this image based on the Dragonfly geometry string.
50
58
  def thumbnail_dimensions(geometry)
51
59
  dimensions = ThumbnailDimensions.new(geometry, image.width, image.height)
52
- { :width => dimensions.width, :height => dimensions.height }
60
+ { width: dimensions.width, height: dimensions.height }
53
61
  end
54
62
 
55
63
  # Returns a titleized version of the filename
@@ -0,0 +1,42 @@
1
+ module Refinery
2
+ module Admin
3
+
4
+ # Refinery::Admin::GridPresenter is a class intended for presenting
5
+ # grouped records in a grid format within the Refinery CMS admin interface.
6
+ #
7
+ # It inherits from Refinery::Admin::GroupPresenter and overrides specific
8
+ # properties to provide custom behavior suitable for grid presentations.
9
+ #
10
+ # The primary features provided by this class include:
11
+ # - Custom grouping of records based on predefined logic.
12
+ # - Control over headers, identity keys, and displayed content organization.
13
+ #
14
+ # == Inclusions
15
+ # This class includes the following modules to extend functionality:
16
+ # - Refinery::Admin::ImagesHelper: Provides helper methods for working with images.
17
+ # - ActionView::Helpers::TagHelper: Supplies methods for creating HTML tags.
18
+ #
19
+ # == Attributes
20
+ # - @group_headers: Controls whether headers for each record group are displayed. Defaults to `false`.
21
+ # - @identity_keys: Represents the keys used to identify and present record attributes, including thumbnail, title, and alt text attributes.
22
+ # - @header: Stores header configurations, initialized as `nil`.
23
+ # - @groups: A lambda function designed to group records by associating them with the current date.
24
+ #
25
+ # == Initialization
26
+ # When initialized, `GridPresenter` accepts an execution `context` (e.g., a controller, view, etc.)
27
+ # and propagates this context to the superclass.
28
+ class GridPresenter < GroupPresenter
29
+ include Refinery::Admin::ImagesHelper
30
+ include ActionView::Helpers::TagHelper
31
+
32
+ def initialize(context)
33
+ super(context)
34
+ @group_headers = false
35
+ @identity_keys = [:thumbnail, :title, :alt]
36
+ @header = nil
37
+ @groups = ->(records) { [[Date.today, records]] }
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,68 @@
1
+ module Refinery
2
+ module Admin
3
+
4
+ # Refinery::Admin::GroupPresenter
5
+ #
6
+ # This class represents a presenter for organizing and displaying
7
+ # groups with associated metadata in a structured format.
8
+ #
9
+ # The presenter utilizes several helper modules for enhanced
10
+ # functionality and template rendering support.
11
+ #
12
+ # == Includes:
13
+ # * `Refinery::Admin::ImagesHelper` - Provides image-related functionality.
14
+ # * `ActionView::Helpers::TagHelper` - Used to create HTML-like tags dynamically.
15
+ #
16
+ # == Attributes:
17
+ # * `context` [Object] - Represents the context within which the presenter operates.
18
+ # * `groups` [Object] - Holds a collection of groups to be managed.
19
+ # * `group_classes` [Array] - Provides a list of CSS class names applied to the group tag.
20
+ # * `group_header` [Proc] - Callable object (e.g., lambda) to determine the header for each group.
21
+ # * `group_headers` [Boolean] - Controls whether group headers are displayed.
22
+ # * `group_tag` [Symbol] - Defines the tag used to wrap groups, e.g., `:ul`.
23
+ # * `group_wrapper` [Proc] - Customizable wrapper for rendering group collections.
24
+ # * `header` [Proc] - Callable object to format the header for individual groups.
25
+ # * `header_tag` [Symbol] - Specifies the tag for rendering headers, e.g., `:h3`.
26
+ # * `identity_keys` [Object] - Additional attribute for handling unique identity keys.
27
+ #
28
+ # == Public Instance Methods:
29
+ # - `initialize(context)`
30
+ # Initializes a new instance of the presenter within a given context,
31
+ # setting default values for various attributes like headers and tags.
32
+ #
33
+ # - `group_wrapper(&block)`
34
+ # Wraps the rendering of groups using a specified tag.
35
+ # This is customizable via the `group_tag` and `group_classes` attributes.
36
+ # A block must be passed to render the inner contents.
37
+ #
38
+ # - `group_header(date)`
39
+ # Constructs a header for individual groups based on a provided date.
40
+ # The format of the header is defined by the `header` callable and
41
+ # displayed using the specified `header_tag`.
42
+ class GroupPresenter
43
+ include Refinery::Admin::ImagesHelper
44
+ include ActionView::Helpers::TagHelper
45
+
46
+ attr_accessor :context, :groups, :group_classes, :group_header, :group_headers, :group_tag, :group_wrapper,
47
+ :header, :header_tag, :identity_keys
48
+
49
+ def initialize(context)
50
+ @context = context
51
+ @group_headers = true
52
+ @group_tag = :ul
53
+ @group_classes = [:image_group]
54
+ @header_tag = :h3
55
+ end
56
+
57
+ def group_wrapper(&block)
58
+ context.tag group_tag, class: group_classes do
59
+ yield block
60
+ end
61
+ end
62
+
63
+ def group_header(date)
64
+ tag.send(header_tag, header.call(date), class: :group_header)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,145 @@
1
+ module Refinery
2
+ module Admin
3
+
4
+ # Refinery::Admin::ImagePresenter
5
+ #
6
+ # This class represents a presenter for managing and displaying image data
7
+ # in the Refinery admin interface. It provides methods to format image-related
8
+ # data for display and to generate necessary HTML components for interacting
9
+ # with images in the admin UI.
10
+ #
11
+ # === Includes
12
+ # - ActionView::RecordIdentifier: Provides methods for DOM ID generation for records.
13
+ # - ActionView::Helpers::UrlHelper: Allows generation of URLs and links.
14
+ # - ActionView::Helpers::TagHelper: Provides methods for generating HTML tags.
15
+ # - ActionView::Context: Allows rendering within the correct context.
16
+ # - Refinery::TranslationHelper: Adds support for translation-related helper methods.
17
+ # - Refinery::Admin::ImagesHelper: Includes specific helper methods for working with images.
18
+ # - Refinery::ActionHelper: Provides additional action-based helper methods.
19
+ #
20
+ # === Attributes
21
+ # - `image` [Reader]: The image object being presented.
22
+ # - `context` [Reader]: Context of the current view, often required for generating paths and URLs.
23
+ # - `index_keys` [Reader]: Used to specify the attributes displayed in the index table for images.
24
+ # - `i18n_scope` [Reader]: Specifies the internationalization scope for localization of text.
25
+ # - `title` [Writer]: Sets the title for the image.
26
+ # - `alt` [Writer]: Sets the alt text for the image.
27
+ # - `filename` [Writer]: Sets the filename for the image.
28
+ # - `translations` [Writer]: Stores translations for the image fields.
29
+ # - `edit_attributes` [Writer]: Stores attributes to be used for editing the image.
30
+ # - `delete_attributes` [Writer]: Stores attributes to be used for deleting the image.
31
+ # - `preview_attributes` [Writer]: Stores attributes for image preview options.
32
+ #
33
+ # === Constants
34
+ # - `IndexEntry`: Defines a structure to hold index entry data, including the image ID,
35
+ # edit link, text elements, locales, and actionable items.
36
+ #
37
+ # === Instance Methods
38
+ #
39
+ # - `initialize(image, context, scope = nil)`:
40
+ # Constructor that initializes the ImagePresenter with the given image object, view context,
41
+ # and optional internationalization scope.
42
+ #
43
+ # - `index_entry(index_keys)`:
44
+ # Generates an index entry for the image, including its ID, edit link, text elements,
45
+ # and actions. Accepts an array of keys for specifying index fields.
46
+ # These keys differ between the grid_view and list_view, and other views could be added
47
+ #
48
+ # - `link_to_edit(edit_key)`:
49
+ # Creates a link to edit the image, using the given key for determining the "text" of the link.
50
+ #
51
+ # - `text_elements(keys)`:
52
+ # Generates text elements for display based on the provided keys, wrapping them in HTML spans.
53
+ #
54
+ # - `thumbnail`:
55
+ # Returns the thumbnail for the image, including specific attributes such as its
56
+ # URL, description (alt) and title
57
+ class ImagePresenter < Refinery::BasePresenter
58
+ include ActionView::RecordIdentifier
59
+ include ActionView::Helpers::UrlHelper
60
+ include ActionView::Helpers::TagHelper
61
+ include ActionView::Context
62
+
63
+ include Refinery::TranslationHelper
64
+ include Refinery::Admin::ImagesHelper
65
+ include Refinery::ActionHelper
66
+
67
+ attr_reader :image, :context, :index_keys, :i18n_scope
68
+ attr_writer :title, :alt, :filename, :translations, :edit_attributes, :delete_attributes, :preview_attributes
69
+ delegate_missing_to :image
70
+ delegate :t, to: :context
71
+
72
+ IndexEntry = Struct.new('ImageEntry', :id, :edit_link, :text_elements, :locales, :actions)
73
+
74
+ def initialize(image, context, scope = nil)
75
+ super(image)
76
+ @image = image
77
+ @context = context
78
+ @i18n_scope = scope || 'refinery.admin.images'
79
+ end
80
+
81
+ def index_entry(index_keys)
82
+ edit_key, *text_keys = index_keys
83
+ IndexEntry.new(
84
+ id: image.id,
85
+ edit_link: link_to_edit(index_keys[0]),
86
+ text_elements: text_elements(index_keys[1..]),
87
+ actions: tag.span( image_actions, class: :actions)
88
+ )
89
+ end
90
+
91
+ def link_to_edit(edit_key)
92
+ link_to(self.send(edit_key),
93
+ context.edit_admin_image_path(image),
94
+ { title: ::I18n.t('.edit', title: image.title, scope: i18n_scope), class: :edit_link})
95
+ end
96
+
97
+ def text_elements(keys)
98
+ keys.reduce(ActiveSupport::SafeBuffer.new) do |buffer, key|
99
+ buffer << tag.span(self.send(key), title: ::I18n.t(key, scope: i18n_scope), class: key)
100
+ end
101
+ end
102
+
103
+ def thumbnail
104
+ tag.img src: image.thumbnail(geometry: Refinery::Images.admin_image_sizes[:grid], strip: true).url(only_path: true),
105
+ alt: image.alt, title: image.title, class: :thumbnail
106
+ end
107
+
108
+ def title
109
+ translated_field(image, :title)
110
+ end
111
+
112
+ def alt
113
+ alt_text = translated_field(@image, :alt)
114
+ alt_text unless alt_text === translated_field(image, :title)
115
+ end
116
+
117
+ def filename
118
+ image.image_name
119
+ end
120
+
121
+ def image_actions
122
+ [*edit_actions, delete_action, preview_action].reduce(ActiveSupport::SafeBuffer.new) do |buffer, action|
123
+ buffer << action
124
+ end
125
+ end
126
+
127
+ def edit_actions
128
+ translated_locales = locales_with_translated_field(image, :image_title)
129
+ edit_in_locales(context.edit_admin_image_path(image), translated_locales)
130
+ end
131
+
132
+ def preview_action(options = {})
133
+ action_icon(:preview, image.url, ::I18n.t('.view_live_html', scope: i18n_scope),
134
+ options: options)
135
+ end
136
+
137
+ def delete_action(options = {})
138
+ action_icon(:delete, context.admin_image_path(image),
139
+ ::I18n.t('.delete', scope: i18n_scope),
140
+ data: { confirm: ::I18n.t('message', scope: 'refinery.admin.delete', title: image.title) },
141
+ **options )
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,23 @@
1
+ module Refinery
2
+ module Admin
3
+ class ListPresenter < GroupPresenter
4
+ include Refinery::Admin::ImagesHelper
5
+ include ActionView::Helpers::TagHelper
6
+
7
+ # Initialize the presenter with a context, a lambda for headers, and a lambda for groups.
8
+ #
9
+ # @param context [Object] An object that provides the necessary methods for grouping and rendering.
10
+ # @param header [Proc] Callable for formatting group headers.
11
+ # @param groups [Proc] Callable for grouping records.
12
+ def initialize(context,
13
+ header: ->(date) { localized(date) },
14
+ groups: ->(records) { context.group_by_date(records, :updated_at) })
15
+ super(context)
16
+ @identity_keys = [:title, :filename, :alt]
17
+ @group_headers = true
18
+ @header = header
19
+ @groups = groups
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ <%= content_tag :li, id: "crop_#{crop.id}" do %>
2
+ <%= image_fu crop, '255x255', class: 'brown_border' %>
3
+ <%= action_icon :delete, refinery.admin_image_crop_path(crop), t('delete', scope: 'refinery.admin.images'),
4
+ class: 'confirm-delete',
5
+ data: { confirm: t('message', scope: 'refinery.admin.delete', title: t('.delete_crop', title: crop.parent.title, id: crop.id) ) },
6
+ remote: true %>
7
+ <% end %>
@@ -2,25 +2,49 @@
2
2
  <%= render '/refinery/admin/search', :url => refinery.insert_admin_images_path(params.to_unsafe_h.dup.except('image')) %>
3
3
  <input type="hidden" name="selected_image" id="selected_image" />
4
4
  <div id="existing_image_area_content" class="clearfix">
5
- <% if @images.any? %>
6
- <ul>
7
- <% @images.each do |image| -%>
8
- <li<%= ' class="selected"'.html_safe if @image_id == image.id %>>
9
- <%= image_fu(image, '106x106#c', {
10
- :alt => image.title,
11
- :title => image.title,
12
- :id => "image_#{image.id}",
13
- :'data-id' => image.id
14
- }.merge(thumbnail_urls(image))) -%>
15
- </li>
16
- <% end -%>
17
- </ul>
18
- <% elsif searching? %>
19
- <%= t('no_results', :scope => 'refinery.admin.search') %>
20
- <% end %>
5
+ <% if @images.any? %>
6
+ <ul class="clearfix">
7
+ <% @images.each do |image| -%>
8
+ <%= content_tag :li, class: ('selected' if @image_id == image.id) do %>
9
+ <%= image_fu(image, '106x106#c',
10
+ alt: image.title,
11
+ title: image.title,
12
+ id: dom_id(image),
13
+ data: {
14
+ id: image.id,
15
+ **thumbnail_urls(image)[:data]
16
+ })-%>
17
+
18
+ <% if image.crops.any? %>
19
+ <div class="crops">
20
+ <ul class="clearfix">
21
+ <% image.crops.each do |crop| %>
22
+ <%= content_tag :li, class: ('selected' if @image_id == image.id) do %>
23
+ <%= image_fu(crop, '106x106>',
24
+ alt: crop.parent.alt,
25
+ title: crop.parent.title,
26
+ id: "image_#{crop.id}",
27
+ data: {
28
+ id: crop.id,
29
+ **thumbnail_urls(crop)[:data]
30
+ }) %>
31
+ <% end %>
32
+ <% end %>
33
+ </ul>
34
+ </div>
35
+ <% end %>
36
+ <% end %>
37
+ <% end %>
38
+ </ul>
39
+ <% elsif searching? %>
40
+ <%= t('no_results', :scope => 'refinery.admin.search') %>
41
+ <% end %>
21
42
  </div>
43
+
22
44
  <%= will_paginate @images, :params => params.to_unsafe_h.dup.merge(:action => "insert") %>
23
45
 
46
+ <div id="existing_image_area_crops" class="clearfix"></div>
47
+
24
48
  <% unless @app_dialog or @images.empty? %>
25
49
  <div id="existing_image_size_area" class="clearfix">
26
50
  <input type="hidden" name="selected_image_size" id="selected_image_size" />
@@ -30,22 +54,23 @@
30
54
  <%= t('.resize_image') %>
31
55
  </label>
32
56
  </p>
33
- <ul>
57
+
58
+ <%= select :resize, nil, nil, { prompt: t('.select_resize') }, { id: 'resize'} do %>
34
59
  <%
35
60
  Refinery::Images.user_image_sizes.sort_by { |key, geometry| geometry.to_i }.each_with_index do |(size, pixels), index|
36
61
  safe_pixels = pixels.to_s.gsub(/[<>=]/, '')
37
62
  # (parndt): ' selected' if size.to_s == 'medium' is not very generic, but I
38
63
  # can't think of a decent way of making it so for even sets (e.g. 2,4,6,8,etc image sizes).
39
- -%>
40
- <li id="image_dialog_size_<%= index %>" class="image_dialog_size<%= ' selected' if size.to_s == 'medium' %>">
41
- <%= link_to size.to_s, "##{size}",
42
- :'data-geometry' => pixels,
43
- :'data-size' => size.to_s.parameterize,
44
- :title => "#{size} image (#{safe_pixels})",
45
- :tooltip => "#{size} image (#{safe_pixels})" %>
46
- </li>
47
- <% end -%>
48
- </ul>
64
+ %>
65
+ <%= content_tag :option,
66
+ "#{size} image (#{safe_pixels})",
67
+ value: size.to_s.parameterize,
68
+ id: "image_dialog_size_#{index}",
69
+ data: { geometry: pixels, size: size.to_s.parameterize },
70
+ selected: (true if size.to_s == 'medium')
71
+ %>
72
+ <% end %>
73
+ <% end %>
49
74
  </div>
50
75
  <% end %>
51
76