udongo 5.2.0 → 5.3.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/backend/articles_controller.rb +57 -0
  3. data/app/forms/backend/article_translation_form.rb +10 -0
  4. data/app/models/article.rb +13 -0
  5. data/app/models/asset.rb +1 -1
  6. data/app/models/user.rb +2 -0
  7. data/app/views/backend/articles/_form.html.erb +33 -0
  8. data/app/views/backend/articles/_tabs.html.erb +23 -0
  9. data/app/views/backend/articles/edit.html.erb +6 -0
  10. data/app/views/backend/articles/edit_translation.html.erb +38 -0
  11. data/app/views/backend/articles/index.html.erb +55 -0
  12. data/app/views/backend/articles/new.html.erb +5 -0
  13. data/app/views/backend/assets/edit.html.erb +1 -1
  14. data/app/views/backend/redirects/index.html.erb +1 -1
  15. data/app/views/layouts/backend/_top_navigation.html.erb +1 -0
  16. data/changelog.md +7 -0
  17. data/config/locales/en_backend.yml +9 -1
  18. data/config/locales/en_forms.yml +4 -0
  19. data/config/locales/nl_backend.yml +9 -1
  20. data/config/locales/nl_forms.yml +3 -0
  21. data/config/routes.rb +5 -0
  22. data/db/migrate/20170305125627_create_articles.rb +17 -0
  23. data/lib/udongo/assets/resizer.rb +81 -0
  24. data/lib/udongo/configs/articles.rb +28 -0
  25. data/lib/udongo/image_manipulation/base.rb +14 -0
  26. data/lib/udongo/image_manipulation/resize_and_pad.rb +38 -0
  27. data/lib/udongo/image_manipulation/resize_to_fill.rb +47 -0
  28. data/lib/udongo/image_manipulation/resize_to_fit.rb +23 -0
  29. data/lib/udongo/image_manipulation/resize_to_limit.rb +24 -0
  30. data/lib/udongo/version.rb +1 -1
  31. data/readme.md +21 -0
  32. data/spec/factories/articles.rb +5 -0
  33. data/spec/support/concerns/publishable.rb +1 -1
  34. metadata +20 -3
  35. data/app/models/asset_image.rb +0 -172
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e6a22b011bc3569827aedbcdd99d353e735fae6e
4
- data.tar.gz: 3202da4e9d86005256c04c4826bc9b0b3eaede7b
3
+ metadata.gz: 9d115e3ef3cee04ca698603e4ee45311fd889657
4
+ data.tar.gz: 2cd47fc1bb20378bf303eeefd266766118cf300c
5
5
  SHA512:
6
- metadata.gz: 0a90d20c8888527092dea454829c2f04cf507f7af964d1d747b3fa10e4473b5dd1753d2051295d7a6ed727d868f5f72a1ce8571f16425b3f1ae1731aa5728792
7
- data.tar.gz: ce3492185bef64ce7b2ccc6786a41089560ac1555a0814ff7ae26c5ba4e92941d15b7f278639652c9b3a9fcc187677d3224a06796c3b8b9a5ec02a7ced5bb802
6
+ metadata.gz: deb6f201c70f981fd121a8cd062b47dd207796db046b0797a50922a1bb39a5856c34ba58fa4fbbbf8ed2a7fc9cb63a2afb91eb3f8b81f5d5a9ad065726266ab7
7
+ data.tar.gz: f9046c6519ed43548a5287de8c7ba8e690df115c34ff2635a592d5f96466885f2d4a7f608dc366f6a1353f26477c11be5e5db49225998c7d07e6f14f623a63ff
@@ -0,0 +1,57 @@
1
+ class Backend::ArticlesController < Backend::BaseController
2
+ include Concerns::Backend::TranslatableController
3
+ include Concerns::PaginationController
4
+
5
+ before_action :find_model, only: [:edit, :update, :destroy]
6
+ before_action -> { breadcrumb.add t('b.articles'), backend_articles_path }
7
+
8
+ def index
9
+ @articles = paginate Article.order('published_at DESC')
10
+ end
11
+
12
+ def new
13
+ @model = Article.new
14
+ end
15
+
16
+ def create
17
+ @model = Article.new(allowed_params)
18
+
19
+ if @model.save
20
+ redirect_to edit_translation_backend_article_path(@model, translation_locale: default_app_locale),
21
+ notice: translate_notice(:added, :article)
22
+ else
23
+ render :new
24
+ end
25
+ end
26
+
27
+ def update
28
+ if @model.update_attributes allowed_params
29
+ redirect_to backend_articles_path, notice: translate_notice(:edited, :article)
30
+ else
31
+ render :edit
32
+ end
33
+ end
34
+
35
+ def destroy
36
+ @model.destroy
37
+ redirect_to backend_articles_path, notice: translate_notice(:deleted, :article)
38
+ end
39
+
40
+ private
41
+
42
+ def find_model
43
+ @model = Article.find(params[:id])
44
+ end
45
+
46
+ def allowed_params
47
+ params[:article].permit(:user_id, :press_release, :published_at, :visible)
48
+ end
49
+
50
+ def translation_form
51
+ Backend::ArticleTranslationForm.new(
52
+ @model,
53
+ @model.translation(params[:translation_locale]),
54
+ @model.seo(params[:translation_locale])
55
+ )
56
+ end
57
+ end
@@ -0,0 +1,10 @@
1
+ class Backend::ArticleTranslationForm < Backend::TranslationWithSeoForm
2
+ attribute :title, String
3
+ attribute :summary, String
4
+
5
+ validates :title, :summary, presence: true
6
+
7
+ def self.model_name
8
+ Article.model_name
9
+ end
10
+ end
@@ -0,0 +1,13 @@
1
+ class Article < ApplicationRecord
2
+ include Concerns::Taggable
3
+ include Concerns::Visible
4
+ include Concerns::Seo
5
+ include Concerns::FlexibleContent
6
+ include Concerns::Searchable
7
+ include Concerns::Publishable
8
+
9
+ include Concerns::Translatable
10
+ translatable_fields :title, :summary
11
+
12
+ belongs_to :user
13
+ end
data/app/models/asset.rb CHANGED
@@ -14,7 +14,7 @@ class Asset < ApplicationRecord
14
14
  end
15
15
 
16
16
  def image
17
- AssetImage.new(self) if image?
17
+ Udongo::Assets::Resizer.new(self) if image?
18
18
  end
19
19
 
20
20
  def actual_filename
data/app/models/user.rb CHANGED
@@ -2,6 +2,8 @@ class User < ActiveRecord::Base
2
2
  include Concerns::Person
3
3
  has_secure_password
4
4
 
5
+ has_many :articles, dependent: :destroy
6
+
5
7
  validates :first_name, :last_name, presence: true
6
8
  validates :email,
7
9
  presence: true,
@@ -0,0 +1,33 @@
1
+ <%= render 'backend/general_form_error', object: @model %>
2
+
3
+ <%= simple_form_for [:backend, @model] do |f| %>
4
+ <div class="row">
5
+ <div class="col-md-8">
6
+ <div class="card">
7
+ <div class="card-header">
8
+ <%= t 'b.general' %>
9
+ </div>
10
+
11
+ <div class="card-block">
12
+ <%= f.input :user_id, collection: User.order(:first_name, :last_name), label_method: :full_name, label: t('b.author') %>
13
+ <%= f.input :published_at, as: :datetime, start_year: 1990, end_year: 2050 %>
14
+ </div>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="col-md-4">
19
+ <div class="card">
20
+ <div class="card-header">
21
+ <%= t 'b.settings' %>
22
+ </div>
23
+
24
+ <div class="card-block">
25
+ <%= f.input :press_release, as: :boolean %>
26
+ <%= f.input :visible, as: :boolean %>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </div>
31
+
32
+ <%= render 'backend/form_actions', cancel_url: backend_articles_path %>
33
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <div class="row subnav">
2
+ <div class="col-md-12">
3
+ <ul class="nav nav-pills">
4
+ <li class="nav-item">
5
+ <% klass = %w(nav-link) %>
6
+ <% klass << 'active' if active == :general %>
7
+
8
+ <%= link_to t('b.general'), edit_backend_article_path(@model), class: klass %>
9
+ </li>
10
+
11
+ <% Udongo.config.i18n.app.locales.each do |locale| %>
12
+ <li class="nav-item">
13
+ <% klass = %w(nav-link) %>
14
+ <% klass << 'active' if active == locale.to_sym %>
15
+
16
+ <%= link_to locale.upcase, edit_translation_backend_article_path(@model, locale), class: klass %>
17
+ </li>
18
+ <% end %>
19
+
20
+ <!-- TODO show the images tab if Udongo.config.articles.images? -->
21
+ </ul>
22
+ </div>
23
+ </div>
@@ -0,0 +1,6 @@
1
+ <% breadcrumb.add @model.title %>
2
+ <% breadcrumb.add t('b.edit') %>
3
+ <%= render 'backend/breadcrumbs' %>
4
+
5
+ <%= render 'tabs', active: :general %>
6
+ <%= render 'form', model: @model %>
@@ -0,0 +1,38 @@
1
+ <% breadcrumb.add @model.title, edit_backend_article_path(@model) %>
2
+ <% breadcrumb.add t('b.edit') %>
3
+ <%= render 'backend/breadcrumbs' %>
4
+
5
+ <%= render 'tabs', active: params[:translation_locale].to_sym %>
6
+ <%= render 'backend/general_form_error', object: @translation %>
7
+
8
+ <%= simple_form_for([:backend, @translation], url: edit_translation_backend_article_path, html: { class: 'no-focus' }) do |f| %>
9
+
10
+ <div class="row">
11
+ <div class="col-md-12">
12
+ <!-- Content -->
13
+ <div class="card">
14
+ <div class="card-header">
15
+ <%= t 'b.content' %>
16
+ </div>
17
+
18
+ <div class="card-block">
19
+ <%= f.input :title %>
20
+
21
+ <% summary_type = Udongo.config.articles.editor_for_summary? ? :ckeditor : :text %>
22
+ <%= f.input :summary, as: summary_type %>
23
+ </div>
24
+ </div>
25
+
26
+ <!-- Flexible Content -->
27
+ <%= render 'backend/content/rows', model: @model, locale: params[:translation_locale] %>
28
+
29
+ <!-- SEO -->
30
+ <%= render 'backend/seo_form', f: f %>
31
+
32
+ <!-- Tags -->
33
+ <%= render 'backend/tags', model: @model %>
34
+ </div>
35
+ </div>
36
+
37
+ <%= render 'backend/form_actions', cancel_url: backend_articles_path %>
38
+ <% end %>
@@ -0,0 +1,55 @@
1
+ <%= render 'backend/breadcrumbs' %>
2
+
3
+ <p class="text-xs-right">
4
+ <%= link_to icon(:plus, t('b.add')), new_backend_article_path, class: 'btn btn-primary btn-sm' %>
5
+ </p>
6
+
7
+ <% if @articles.any? %>
8
+ <table class="table table-striped table-hover">
9
+ <thead class="thead-inverse">
10
+ <tr>
11
+ <th><%= t 'b.title' %></th>
12
+ <th><%= t 'b.author' %></th>
13
+ <th><%= t 'b.published_at' %></th>
14
+ <th><%= t 'b.visible' %></th>
15
+ <th><%= t 'b.press_release' %></th>
16
+ <th>&nbsp;</th>
17
+ </tr>
18
+ </thead>
19
+
20
+ <tbody>
21
+ <% @articles.each do |a| %>
22
+ <tr class="<%= 'text-muted' if a.hidden? || a.unpublished? %>">
23
+ <td>
24
+ <% if a.title.blank? %>
25
+ <%= link_to edit_translation_backend_article_path(a, default_app_locale) do %>
26
+ <%= icon(:exclamation_triangle) %>
27
+ <%= t('b.msg.no_title_set') %>
28
+ <% end %>
29
+ <% else %>
30
+ <%= a.title %>
31
+ <% end %>
32
+ </td>
33
+ <td>
34
+ <% if a.user.present? %>
35
+ <%= link_to icon(:user, a.user.full_name), edit_backend_user_path(a.user) %>
36
+ <% else %>
37
+ <%= t 'b.not_set' %>
38
+ <% end %>
39
+ </td>
40
+ <td><%= l a.published_at if a.published_at %></td>
41
+ <td><%= t a.visible?.to_s %></td>
42
+ <td><%= t a.press_release?.to_s %></td>
43
+ <td class="text-xs-right">
44
+ <%= link_to_edit [:backend, a] %>
45
+ <%= link_to_delete [:backend, a] %>
46
+ </td>
47
+ </tr>
48
+ <% end %>
49
+ </tbody>
50
+ </table>
51
+
52
+ <%= udongo_paginate @articles %>
53
+ <% else %>
54
+ <p><%= t 'b.msg.no_items' %></p>
55
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% breadcrumb.add t('b.add') %>
2
+ <%= render 'backend/breadcrumbs' %>
3
+
4
+ <%= render 'form' %>
5
+
@@ -1,4 +1,4 @@
1
- <% breadcrumb.add truncate(@model.description, length: 20), edit_backend_snippet_path(@model) %>
1
+ <% breadcrumb.add truncate(@model.description, length: 20), edit_backend_asset_path(@model) %>
2
2
  <% breadcrumb.add t('b.edit') %>
3
3
  <%= render 'backend/breadcrumbs' %>
4
4
 
@@ -13,7 +13,7 @@
13
13
  <th><%= t 'b.source' %></th>
14
14
  <th><%= t 'b.destination' %></th>
15
15
  <th><%= t 'b.status_code' %></th>
16
- <th><%= t 'b.enabled?' %></th>
16
+ <th><%= t 'b.enabled' %></th>
17
17
  <th><%= t 'b.used' %></th>
18
18
  <th>&nbsp;</th>
19
19
  </tr>
@@ -3,6 +3,7 @@
3
3
  <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false"><%= icon(:list, t('b.content')) %></a>
4
4
  <div class="dropdown-menu">
5
5
  <%= link_to t('b.pages'), backend_pages_path, class: 'dropdown-item' %>
6
+ <%= link_to t('b.articles'), backend_articles_path, class: 'dropdown-item' %>
6
7
  <%= link_to t('b.snippets'), backend_snippets_path, class: 'dropdown-item' %>
7
8
  <%= link_to t('b.files'), backend_assets_path, class: 'dropdown-item' %>
8
9
  </div>
data/changelog.md CHANGED
@@ -1,3 +1,10 @@
1
+ 5.3.0 - 2017-03-07
2
+ --
3
+ * Refactor the asset image resizer(s).
4
+ * Add a basic articles module.
5
+ * You can configure the article module with some settings. See the readme.
6
+
7
+
1
8
  5.2.0 - 2017-03-02
2
9
  --
3
10
  * Add an assets module to manage all kinds of files.
@@ -6,6 +6,9 @@ en:
6
6
  admin: Admin
7
7
  admins: Admins
8
8
  advanced: Advanced
9
+ article: Article
10
+ articles: Articles
11
+ author: Author
9
12
  cancel: Cancel
10
13
  content: Content
11
14
  current_image: Current image
@@ -21,7 +24,7 @@ en:
21
24
  emails: E-mails
22
25
  email_template: E-mail template
23
26
  email_templates: E-mail templates
24
- enabled?: Enabled?
27
+ enabled: Enabled
25
28
  extra: Extra
26
29
  file: File
27
30
  files: Files
@@ -43,11 +46,14 @@ en:
43
46
  navigation_item: Navigation item
44
47
  new: New
45
48
  none: None
49
+ not_set: Not set
46
50
  not_yet_sent: Not yet sent
47
51
  page: Page
48
52
  pages: Pages
49
53
  password: Password
50
54
  plain_content: Plain content
55
+ press_release: Press release
56
+ published_at: Published at
51
57
  recipient: Recipient
52
58
  redirect: Redirect
53
59
  redirects: Redirects
@@ -77,6 +83,7 @@ en:
77
83
  users: Users
78
84
  variables: Variables
79
85
  view: View
86
+ visible: Visible
80
87
 
81
88
  msg:
82
89
  added: '%s was added.'
@@ -107,6 +114,7 @@ en:
107
114
  navigation:
108
115
  custom: Custom
109
116
  no_items: There are no items.
117
+ no_title_set: This item has not title.
110
118
  pages:
111
119
  invisible: Deze pagina is niet zichtbaar op de website.
112
120
  saved: '%s was saved.'
@@ -13,6 +13,7 @@ en:
13
13
 
14
14
  labels:
15
15
  defaults:
16
+ active: Active
16
17
  bcc: BCC
17
18
  caption: Caption
18
19
  category: Category
@@ -34,6 +35,8 @@ en:
34
35
  password_confirmation: Password confirmation
35
36
  phone: Phone
36
37
  plain_content: Plain content
38
+ press_release: Press release?
39
+ published_at: Published at
37
40
  seo_title: Page title
38
41
  seo_slug: Custom URL
39
42
  seo_description: Description
@@ -44,6 +47,7 @@ en:
44
47
  summary: Summary
45
48
  synonyms: Synonyms
46
49
  title: Title
50
+ user_id: User
47
51
  visible: Visible?
48
52
  width: Width
49
53
  url: URL
@@ -6,6 +6,9 @@ nl:
6
6
  admin: Beheerder
7
7
  admins: Beheerders
8
8
  advanced: Geavanceerd
9
+ article: Artikel
10
+ articles: Artikels
11
+ author: Auteur
9
12
  cancel: Annuleren
10
13
  content: Inhoud
11
14
  current_image: Huidige afbeelding
@@ -21,7 +24,7 @@ nl:
21
24
  emails: E-mails
22
25
  email_template: E-mail template
23
26
  email_templates: E-mail templates
24
- enabled?: Ingeschakeld?
27
+ enabled: Ingeschakeld
25
28
  extra: Extra
26
29
  file: Bestand
27
30
  files: Bestanden
@@ -43,11 +46,14 @@ nl:
43
46
  navigation_item: Navigatie-item
44
47
  new: Nieuw
45
48
  none: Geen
49
+ not_set: Niet ingesteld
46
50
  not_yet_sent: Nog niet verzonden
47
51
  page: Pagina
48
52
  pages: Pagina's
49
53
  password: Wachtwoord
50
54
  plain_content: Tekst inhoud
55
+ press_release: Persbericht
56
+ published_at: Gepubliceerd op
51
57
  recipient: Bestemmeling
52
58
  redirect: Redirect
53
59
  redirects: Redirects
@@ -77,6 +83,7 @@ nl:
77
83
  users: Gebruikers
78
84
  variables: Variabelen
79
85
  view: Bekijk
86
+ visible: Zichtbaar
80
87
 
81
88
  msg:
82
89
  added: '%{actor} werd toegevoegd.'
@@ -107,6 +114,7 @@ nl:
107
114
  navigation:
108
115
  custom: Op maat
109
116
  no_items: Er zijn geen items.
117
+ no_title_set: Dit item heeft nog geen titel.
110
118
  pages:
111
119
  invisible: Deze pagina is niet zichtbaar op de website.
112
120
  saved: '%{actor} werd bewaard.'
@@ -35,6 +35,8 @@ nl:
35
35
  password_confirmation: Wachtwoord bevestiging
36
36
  phone: Telefoonnummer
37
37
  plain_content: Tekstuele inhoud
38
+ press_release: Persbericht?
39
+ published_at: Gepubliceerd op
38
40
  seo_title: Paginatitel
39
41
  seo_slug: Aangepaste URL
40
42
  seo_description: Beschrijving
@@ -45,6 +47,7 @@ nl:
45
47
  summary: Korte inhoud
46
48
  synonyms: Synoniemen
47
49
  title: Titel
50
+ user_id: Gebruiker
48
51
  visible: Zichtbaar?
49
52
  width: Breedte
50
53
  url: URL
data/config/routes.rb CHANGED
@@ -24,11 +24,16 @@ Rails.application.routes.draw do
24
24
 
25
25
  resources :pages, except: [:show] do
26
26
  concerns :translatable
27
+
27
28
  member do
28
29
  post :tree_drag_and_drop, :toggle_visibility
29
30
  end
30
31
  end
31
32
 
33
+ resources :articles, except: [:show] do
34
+ concerns :translatable
35
+ end
36
+
32
37
  resources :navigations, only: [:index] do
33
38
  scope module: 'navigation' do
34
39
  resources :items, except: [:index, :show] do
@@ -0,0 +1,17 @@
1
+ class CreateArticles < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :articles do |t|
4
+ t.references :user
5
+ t.boolean :press_release
6
+ t.datetime :published_at
7
+ t.text :locales
8
+ t.boolean :visible
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :articles, :press_release
14
+ add_index :articles, :visible
15
+ add_index :articles, :published_at
16
+ end
17
+ end
@@ -0,0 +1,81 @@
1
+ require 'fileutils'
2
+
3
+ module Udongo
4
+ module Assets
5
+ class Resizer
6
+ def initialize(asset)
7
+ @asset = asset
8
+ end
9
+
10
+ def filename(width = nil, height = nil, options = {})
11
+ action = options.key?(:action) ? options[:action] : :resize_to_limit
12
+ quality = options[:quality]
13
+ gravity = options[:gravity].to_s.underscore.split('_').map { |s| s[0,1] }.join
14
+ background = options[:background].to_s.parameterize
15
+
16
+ str = action.to_s.split('_').last
17
+ str << "-q#{quality}" if quality.present?
18
+ str << "-g#{gravity}" if gravity.present?
19
+ str << "-b#{background}" if background.present?
20
+ str << "-#{width}x#{height}-#{@asset.actual_filename}"
21
+ end
22
+
23
+ def url(width = nil, height = nil, options = {})
24
+ options[:action] = :resize_to_limit unless options.key?(:action)
25
+
26
+ if width.nil? && height.nil?
27
+ return "/uploads/assets/#{main_dir}/#{second_dir}/#{@asset.actual_filename}"
28
+ end
29
+
30
+ name = filename(width, height, options)
31
+
32
+ unless File.exists?(actual_path(name))
33
+ FileUtils.mkpath(File.dirname(actual_path(name)))
34
+
35
+ unless resize_action_allowed? options[:action]
36
+ raise "No such resize action '#{options[:action].to_s}'. Available are: resize_to_limit, resize_to_fit, resize_to_fill and resize_and_pad."
37
+ end
38
+
39
+ trigger_resize(width, height, options)
40
+ end
41
+
42
+ actual_url(name)
43
+ end
44
+
45
+ def actual_url(calculated_filename)
46
+ "/uploads/assets/_cache/#{main_dir}/#{second_dir}/#{calculated_filename}"
47
+ end
48
+
49
+ def path(width = nil, height = nil, options = {})
50
+ url(width, height, options) # Trigger the actual resize (if needed)
51
+ actual_path(filename(width, height, options))
52
+ end
53
+
54
+ def actual_path(calculated_filename)
55
+ "#{Rails.root}/public/uploads/assets/_cache/#{main_dir}/#{second_dir}/#{calculated_filename}"
56
+ end
57
+
58
+ private
59
+
60
+ def trigger_resize(width, height, options = {})
61
+ "Udongo::ImageManipulation::#{options[:action].to_s.camelcase}".constantize.new(
62
+ @asset.filename.path, width, height, options
63
+ ).resize(
64
+ actual_path(filename(width, height, options))
65
+ )
66
+ end
67
+
68
+ def resize_action_allowed?(action)
69
+ %w(resize_to_limit resize_to_fit resize_to_fill resize_and_pad).include?(action.to_s)
70
+ end
71
+
72
+ def main_dir
73
+ @main_dir ||= Digest::MD5.hexdigest(@asset.id.to_s)[0,2]
74
+ end
75
+
76
+ def second_dir
77
+ @second_dir ||= Digest::MD5.hexdigest(@asset.id.to_s)[2,2]
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,28 @@
1
+ module Udongo
2
+ module Configs
3
+ class Articles
4
+ include Virtus.model
5
+
6
+ attribute :allow_html_in_title, Axiom::Types::Boolean, default: false
7
+ attribute :allow_html_in_summary, Axiom::Types::Boolean, default: false
8
+ attribute :editor_for_summary, Axiom::Types::Boolean, default: false
9
+ attribute :images, Axiom::Types::Boolean, default: false
10
+
11
+ def allow_html_in_title?
12
+ allow_html_in_title === true
13
+ end
14
+
15
+ def allow_html_in_summary?
16
+ allow_html_in_summary === true
17
+ end
18
+
19
+ def editor_for_summary?
20
+ editor_for_summary === true
21
+ end
22
+
23
+ def images?
24
+ images === true
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ require 'mini_magick'
2
+
3
+ module Udongo
4
+ module ImageManipulation
5
+ module Base
6
+ def initialize(file, width, height, options = {})
7
+ @file = file
8
+ @width = width
9
+ @height = height
10
+ @options = options
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ require 'mini_magick'
2
+
3
+ module Udongo
4
+ module ImageManipulation
5
+ class ResizeAndPad
6
+ include Base
7
+
8
+ # Resize the image to fit within the specified dimensions while retaining
9
+ # the original aspect ratio. If necessary, will pad the remaining area
10
+ # with the given color, which defaults to transparent (for gif and png,
11
+ # white for jpeg).
12
+ #
13
+ # Possible values for options[:gravity] are:
14
+ # NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast
15
+ #
16
+ def resize(path)
17
+ gravity = @options.key?(:gravity) ? @options[:gravity] : 'Center'
18
+ background = @options.key?(:background) ? @options[:background] : :transparant
19
+
20
+ img = MiniMagick::Image.open(@file)
21
+ img.combine_options do |cmd|
22
+ cmd.thumbnail "#{@width}x#{@height}>"
23
+
24
+ if background.to_sym == :transparent
25
+ cmd.background 'rgba(255, 255, 255, 0.0)'
26
+ else
27
+ cmd.background background
28
+ end
29
+
30
+ cmd.gravity gravity
31
+ cmd.extent "#{@width}x#{@height}"
32
+ end
33
+
34
+ img.write(path)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,47 @@
1
+ require 'mini_magick'
2
+
3
+ module Udongo
4
+ module ImageManipulation
5
+ class ResizeToFill
6
+ include Base
7
+
8
+ # Resize the image to fit within the specified dimensions while retaining
9
+ # the aspect ratio of the original image. If necessary, crop the image in the
10
+ # larger dimension.
11
+ #
12
+ # Possible values for options[:gravity] are:
13
+ # NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast
14
+ #
15
+ def resize(path)
16
+ gravity = @options.key?(:gravity) ? @options[:gravity] : 'Center'
17
+
18
+ img = MiniMagick::Image.open(@file)
19
+ cols, rows = img[:dimensions]
20
+
21
+ img.combine_options do |cmd|
22
+ if @width != cols || @height != rows
23
+ scale_x = @width/cols.to_f
24
+ scale_y = @height/rows.to_f
25
+
26
+ if scale_x >= scale_y
27
+ cols = (scale_x * (cols + 0.5)).round
28
+ rows = (scale_x * (rows + 0.5)).round
29
+ cmd.resize "#{cols}"
30
+ else
31
+ cols = (scale_y * (cols + 0.5)).round
32
+ rows = (scale_y * (rows + 0.5)).round
33
+ cmd.resize "x#{rows}"
34
+ end
35
+ end
36
+
37
+ cmd.quality @options[:quality] if @options.key?(:quality)
38
+ cmd.gravity gravity
39
+ cmd.background 'rgba(255,255,255,0.0)'
40
+ cmd.extent "#{@width}x#{@height}" if cols != @width || rows != @height
41
+ end
42
+
43
+ img.write(path)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ require 'mini_magick'
2
+
3
+ module Udongo
4
+ module ImageManipulation
5
+ class ResizeToFit
6
+ include Base
7
+
8
+ # Resize the image to fit within the specified dimensions while retaining
9
+ # the original aspect ratio. The image may be shorter or narrower than
10
+ # specified in the smaller dimension but will not be larger than the specified values.
11
+ #
12
+ def resize(path)
13
+ img = MiniMagick::Image.open(@file)
14
+ img.combine_options do |c|
15
+ c.quality @options[:quality] if @options[:quality]
16
+ c.resize "#{@width}x#{@height}"
17
+ end
18
+
19
+ img.write(path)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ require 'mini_magick'
2
+
3
+ module Udongo
4
+ module ImageManipulation
5
+ class ResizeToLimit
6
+ include Base
7
+
8
+ # Resize the image to fit within the specified dimensions while retaining
9
+ # the original aspect ratio. Will only resize the image if it is larger than the
10
+ # specified dimensions. The resulting image may be shorter or narrower than specified
11
+ # in the smaller dimension but will not be larger than the specified values.
12
+ #
13
+ def resize(path)
14
+ img = MiniMagick::Image.open(@file)
15
+ img.combine_options do |c|
16
+ c.quality @options[:quality] if @options[:quality]
17
+ c.resize "#{@width}x#{@height}>"
18
+ end
19
+
20
+ img.write(path)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module Udongo
2
- VERSION = '5.2.0'
2
+ VERSION = '5.3.0'
3
3
  end
data/readme.md CHANGED
@@ -72,6 +72,27 @@ Udongo.config.image_white_list = %w(gif jpeg jpg png)
72
72
  Udongo.config.file_white_list = %w(doc docx pdf txt xls xlsx)
73
73
  ```
74
74
 
75
+ ## Articles
76
+ ### allow_html_in_title
77
+ ```ruby
78
+ Udongo.config.articles.allow_html_in_title = false
79
+ ```
80
+
81
+ ### allow_html_in_summary
82
+ ```ruby
83
+ Udongo.config.articles.allow_html_in_summary = false
84
+ ```
85
+
86
+ ### editor_for_summary
87
+ ```ruby
88
+ Udongo.config.articles.editor_for_summary = false
89
+ ```
90
+
91
+ ### images
92
+ ```ruby
93
+ Udongo.config.articles.images = false
94
+ ```
95
+
75
96
  # Concerns
76
97
  ## Storable concern
77
98
  ### Possible field types
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :article do
3
+ user
4
+ end
5
+ end
@@ -28,7 +28,7 @@ shared_examples_for :publishable do
28
28
  it '#unpublish!' do
29
29
  instance.published_at = Time.zone.now
30
30
  instance.unpublish!
31
- expect(instance).not_to be_unpublished
31
+ expect(instance).to be_unpublished
32
32
  end
33
33
 
34
34
  it '.respond_to?' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: udongo
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davy Hellemans
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-03-02 00:00:00.000000000 Z
12
+ date: 2017-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -451,6 +451,7 @@ files:
451
451
  - app/assets/stylesheets/backend/pages/_login.scss
452
452
  - app/assets/stylesheets/backend/udongo.scss
453
453
  - app/controllers/backend/admins_controller.rb
454
+ - app/controllers/backend/articles_controller.rb
454
455
  - app/controllers/backend/assets_controller.rb
455
456
  - app/controllers/backend/base_controller.rb
456
457
  - app/controllers/backend/content/rows/columns_controller.rb
@@ -487,6 +488,7 @@ files:
487
488
  - app/decorators/pagination_decorator.rb
488
489
  - app/decorators/redirect_decorator.rb
489
490
  - app/decorators/snippet_decorator.rb
491
+ - app/forms/backend/article_translation_form.rb
490
492
  - app/forms/backend/email_template_translation_form.rb
491
493
  - app/forms/backend/navigation_item_translation_form.rb
492
494
  - app/forms/backend/page_translation_form.rb
@@ -505,8 +507,8 @@ files:
505
507
  - app/models/address.rb
506
508
  - app/models/admin.rb
507
509
  - app/models/application_record.rb
510
+ - app/models/article.rb
508
511
  - app/models/asset.rb
509
- - app/models/asset_image.rb
510
512
  - app/models/ckeditor/asset.rb
511
513
  - app/models/ckeditor/attachment_file.rb
512
514
  - app/models/ckeditor/picture.rb
@@ -579,6 +581,12 @@ files:
579
581
  - app/views/backend/admins/edit.html.erb
580
582
  - app/views/backend/admins/index.html.erb
581
583
  - app/views/backend/admins/new.html.erb
584
+ - app/views/backend/articles/_form.html.erb
585
+ - app/views/backend/articles/_tabs.html.erb
586
+ - app/views/backend/articles/edit.html.erb
587
+ - app/views/backend/articles/edit_translation.html.erb
588
+ - app/views/backend/articles/index.html.erb
589
+ - app/views/backend/articles/new.html.erb
582
590
  - app/views/backend/assets/_filter.html.erb
583
591
  - app/views/backend/assets/_form.html.erb
584
592
  - app/views/backend/assets/edit.html.erb
@@ -735,14 +743,17 @@ files:
735
743
  - db/migrate/20170215132531_add_active_to_users.rb
736
744
  - db/migrate/20170225144523_create_assets.rb
737
745
  - db/migrate/20170228183831_create_images.rb
746
+ - db/migrate/20170305125627_create_articles.rb
738
747
  - lib/tasks/task_extras.rb
739
748
  - lib/tasks/udongo_tasks.rake
740
749
  - lib/udongo.rb
741
750
  - lib/udongo/active_model_simulator.rb
742
751
  - lib/udongo/assets/loader.rb
743
752
  - lib/udongo/assets/precompiler.rb
753
+ - lib/udongo/assets/resizer.rb
744
754
  - lib/udongo/breadcrumb.rb
745
755
  - lib/udongo/config.rb
756
+ - lib/udongo/configs/articles.rb
746
757
  - lib/udongo/configs/assets.rb
747
758
  - lib/udongo/configs/base.rb
748
759
  - lib/udongo/configs/flexible_content.rb
@@ -757,6 +768,11 @@ files:
757
768
  - lib/udongo/engine.rb
758
769
  - lib/udongo/flexible_content/column_width_calculator.rb
759
770
  - lib/udongo/form.rb
771
+ - lib/udongo/image_manipulation/base.rb
772
+ - lib/udongo/image_manipulation/resize_and_pad.rb
773
+ - lib/udongo/image_manipulation/resize_to_fill.rb
774
+ - lib/udongo/image_manipulation/resize_to_fit.rb
775
+ - lib/udongo/image_manipulation/resize_to_limit.rb
760
776
  - lib/udongo/meta_info.rb
761
777
  - lib/udongo/notification.rb
762
778
  - lib/udongo/object_path.rb
@@ -775,6 +791,7 @@ files:
775
791
  - readme.md
776
792
  - spec/factories/addresses.rb
777
793
  - spec/factories/admins.rb
794
+ - spec/factories/articles.rb
778
795
  - spec/factories/assets.rb
779
796
  - spec/factories/comments.rb
780
797
  - spec/factories/content_columns.rb
@@ -1,172 +0,0 @@
1
- require 'mini_magick'
2
- require 'fileutils'
3
-
4
- class AssetImage
5
- def initialize(asset)
6
- @asset = asset
7
- end
8
-
9
- def filename(width = nil, height = nil, options = {})
10
- options[:action] = :resize_to_limit unless options.key?(:action)
11
-
12
- str = options[:action].to_s.split('_').last
13
-
14
- if options[:quality]
15
- str << '-q' + options[:quality].to_s
16
- end
17
-
18
- if options[:gravity]
19
- str << '-g' + options[:gravity].to_s.underscore.split('_').map { |s| s[0,1] }.join
20
- end
21
-
22
- if options[:background]
23
- str << '-b' + options[:background].to_s.parameterize
24
- end
25
-
26
- str << "-#{width}x#{height}-#{@asset.actual_filename}"
27
- end
28
-
29
- def url(width = nil, height = nil, options = {})
30
- options[:action] = :resize_to_limit unless options.key?(:action)
31
-
32
- if width.nil? && height.nil?
33
- return "/uploads/assets/#{main_dir}/#{second_dir}/#{@asset.actual_filename}"
34
- end
35
-
36
- name = filename(width, height, options)
37
-
38
- unless File.exists?(actual_path(name))
39
- FileUtils.mkpath(File.dirname(actual_path(name)))
40
-
41
- case options[:action].to_sym
42
- when :resize_to_limit then resize_to_limit(width, height, options)
43
- when :resize_to_fit then resize_to_fit(width, height, options)
44
- when :resize_to_fill then resize_to_fill(width, height, options)
45
- when :resize_and_pad then resize_and_pad(width, height, options)
46
- else
47
- raise "No such resize action '#{options[:action].to_s}'. Available are: resize_to_limit, resize_to_fit, resize_to_fill and resize_and_pad."
48
- end
49
- end
50
-
51
- actual_url(name)
52
- end
53
-
54
- def actual_url(calculated_filename)
55
- "/uploads/assets/_cache/#{main_dir}/#{second_dir}/#{calculated_filename}"
56
- end
57
-
58
- def path(width = nil, height = nil, options = {})
59
- url(width, height, options) # Trigger the actual resize
60
- actual_path(filename(width, height, options))
61
- end
62
-
63
- def actual_path(calculated_filename)
64
- "#{Rails.root}/public/uploads/assets/_cache/#{main_dir}/#{second_dir}/#{calculated_filename}"
65
- end
66
-
67
- private
68
-
69
- # Resize the image to fit within the specified dimensions while retaining
70
- # the original aspect ratio. Will only resize the image if it is larger than the
71
- # specified dimensions. The resulting image may be shorter or narrower than specified
72
- # in the smaller dimension but will not be larger than the specified values.
73
- #
74
- def resize_to_limit(width, height, options = {})
75
- img = MiniMagick::Image.open(@asset.filename.path)
76
- img.combine_options do |c|
77
- c.quality options[:quality] if options[:quality]
78
- c.resize "#{width}x#{height}>"
79
- end
80
-
81
- img.write(actual_path(filename(width, height, options)))
82
- end
83
-
84
- # Resize the image to fit within the specified dimensions while retaining
85
- # the original aspect ratio. The image may be shorter or narrower than
86
- # specified in the smaller dimension but will not be larger than the specified values.
87
- #
88
- def resize_to_fit(width, height, options = {})
89
- img = MiniMagick::Image.open(@asset.filename.path)
90
- img.combine_options do |c|
91
- c.quality options[:quality] if options[:quality]
92
- c.resize "#{width}x#{height}"
93
- end
94
-
95
- img.write(actual_path(filename(width, height, options)))
96
- end
97
-
98
- # Resize the image to fit within the specified dimensions while retaining
99
- # the aspect ratio of the original image. If necessary, crop the image in the
100
- # larger dimension.
101
- #
102
- # Possible values for options[:gravity] are:
103
- # NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast
104
- #
105
- def resize_to_fill(width, height, options = {})
106
- gravity = options.key?(:gravity) ? options[:gravity] : 'Center'
107
-
108
- img = MiniMagick::Image.open(@asset.filename.path)
109
- cols, rows = img[:dimensions]
110
-
111
- img.combine_options do |cmd|
112
- if width != cols || height != rows
113
- scale_x = width/cols.to_f
114
- scale_y = height/rows.to_f
115
-
116
- if scale_x >= scale_y
117
- cols = (scale_x * (cols + 0.5)).round
118
- rows = (scale_x * (rows + 0.5)).round
119
- cmd.resize "#{cols}"
120
- else
121
- cols = (scale_y * (cols + 0.5)).round
122
- rows = (scale_y * (rows + 0.5)).round
123
- cmd.resize "x#{rows}"
124
- end
125
- end
126
-
127
- cmd.quality options[:quality] if options.key?(:quality)
128
- cmd.gravity gravity
129
- cmd.background 'rgba(255,255,255,0.0)'
130
- cmd.extent "#{width}x#{height}" if cols != width || rows != height
131
- end
132
-
133
- img.write(actual_path(filename(width, height, options)))
134
- end
135
-
136
- # Resize the image to fit within the specified dimensions while retaining
137
- # the original aspect ratio. If necessary, will pad the remaining area
138
- # with the given color, which defaults to transparent (for gif and png,
139
- # white for jpeg).
140
- #
141
- # Possible values for options[:gravity] are:
142
- # NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast
143
- #
144
- def resize_and_pad(width, height, options = {})
145
- gravity = options.key?(:gravity) ? options[:gravity] : 'Center'
146
- background = options.key?(:background) ? options[:background] : :transparant
147
-
148
- img = MiniMagick::Image.open(@asset.filename.path)
149
- img.combine_options do |cmd|
150
- cmd.thumbnail "#{width}x#{height}>"
151
-
152
- if background.to_sym == :transparent
153
- cmd.background 'rgba(255, 255, 255, 0.0)'
154
- else
155
- cmd.background background
156
- end
157
-
158
- cmd.gravity gravity
159
- cmd.extent "#{width}x#{height}"
160
- end
161
-
162
- img.write(actual_path(filename(width, height, options)))
163
- end
164
-
165
- def main_dir
166
- @main_dir ||= Digest::MD5.hexdigest(@asset.id.to_s)[0,2]
167
- end
168
-
169
- def second_dir
170
- @second_dir ||= Digest::MD5.hexdigest(@asset.id.to_s)[2,2]
171
- end
172
- end