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.
- checksums.yaml +4 -4
- data/app/controllers/backend/articles_controller.rb +57 -0
- data/app/forms/backend/article_translation_form.rb +10 -0
- data/app/models/article.rb +13 -0
- data/app/models/asset.rb +1 -1
- data/app/models/user.rb +2 -0
- data/app/views/backend/articles/_form.html.erb +33 -0
- data/app/views/backend/articles/_tabs.html.erb +23 -0
- data/app/views/backend/articles/edit.html.erb +6 -0
- data/app/views/backend/articles/edit_translation.html.erb +38 -0
- data/app/views/backend/articles/index.html.erb +55 -0
- data/app/views/backend/articles/new.html.erb +5 -0
- data/app/views/backend/assets/edit.html.erb +1 -1
- data/app/views/backend/redirects/index.html.erb +1 -1
- data/app/views/layouts/backend/_top_navigation.html.erb +1 -0
- data/changelog.md +7 -0
- data/config/locales/en_backend.yml +9 -1
- data/config/locales/en_forms.yml +4 -0
- data/config/locales/nl_backend.yml +9 -1
- data/config/locales/nl_forms.yml +3 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20170305125627_create_articles.rb +17 -0
- data/lib/udongo/assets/resizer.rb +81 -0
- data/lib/udongo/configs/articles.rb +28 -0
- data/lib/udongo/image_manipulation/base.rb +14 -0
- data/lib/udongo/image_manipulation/resize_and_pad.rb +38 -0
- data/lib/udongo/image_manipulation/resize_to_fill.rb +47 -0
- data/lib/udongo/image_manipulation/resize_to_fit.rb +23 -0
- data/lib/udongo/image_manipulation/resize_to_limit.rb +24 -0
- data/lib/udongo/version.rb +1 -1
- data/readme.md +21 -0
- data/spec/factories/articles.rb +5 -0
- data/spec/support/concerns/publishable.rb +1 -1
- metadata +20 -3
- data/app/models/asset_image.rb +0 -172
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d115e3ef3cee04ca698603e4ee45311fd889657
|
4
|
+
data.tar.gz: 2cd47fc1bb20378bf303eeefd266766118cf300c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,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
data/app/models/user.rb
CHANGED
@@ -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,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> </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 %>
|
@@ -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
@@ -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
|
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.'
|
data/config/locales/en_forms.yml
CHANGED
@@ -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
|
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.'
|
data/config/locales/nl_forms.yml
CHANGED
@@ -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,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
|
data/lib/udongo/version.rb
CHANGED
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
|
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.
|
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-
|
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
|
data/app/models/asset_image.rb
DELETED
@@ -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
|