aaf-lipstick 4.2.0 → 4.6.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 +5 -5
- data/lib/lipstick/auto_validation.rb +2 -2
- data/lib/lipstick/filterable.rb +1 -0
- data/lib/lipstick/helpers/bootstrap_form_builder.rb +4 -4
- data/lib/lipstick/helpers/form_helper.rb +13 -11
- data/lib/lipstick/helpers/form_validation_builder.rb +1 -3
- data/lib/lipstick/helpers/layout_helper.rb +2 -2
- data/lib/lipstick/helpers/nav_helper.rb +4 -4
- data/lib/lipstick/helpers/sortable_helper.rb +7 -7
- data/lib/lipstick/images.rb +1 -0
- data/lib/lipstick/images/email_banner.rb +10 -5
- data/lib/lipstick/images/logo_only_email_banner.rb +130 -0
- data/lib/lipstick/images/processor.rb +20 -3
- data/lib/lipstick/version.rb +1 -1
- metadata +24 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e1169058e87d4e424cc8ce2591249b54dd0902d05eecfc17afc82999a138c953
|
4
|
+
data.tar.gz: df5e54e75c7bec1f17d373f4af40acf488f1827aec3212a0c6a7d98244aa082b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5be585896864525226c357e68a03d7e7068c2ad7794729c561d335a8cb0b7a11950d27d75424dfc4cc00ce125538bf5ec3fd2a32870ea008c27496a62835df0
|
7
|
+
data.tar.gz: 58e9d15f2b0b00990f16d07a08adffe71e5f205f5aff054542db5728bc16567e41327a0d0202616a314c8ba254dc7476cd835464493e30b914f0e586f29f1722
|
@@ -7,8 +7,8 @@ module Lipstick
|
|
7
7
|
return if base.respond_to?(:validators)
|
8
8
|
|
9
9
|
raise('Lipstick::AutoValidation requires a class which responds' \
|
10
|
-
|
11
|
-
|
10
|
+
' to the `validators` method. For example, as provided by' \
|
11
|
+
' ActiveModel::Validations')
|
12
12
|
end
|
13
13
|
|
14
14
|
def lipstick_auto_validators
|
data/lib/lipstick/filterable.rb
CHANGED
@@ -27,20 +27,20 @@ class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
|
|
27
27
|
super
|
28
28
|
end
|
29
29
|
|
30
|
-
def check_box(
|
30
|
+
def check_box(*, &block)
|
31
31
|
template.content_tag('div', class: 'checkbox') do
|
32
32
|
template.content_tag('label') do
|
33
33
|
template.concat(super)
|
34
|
-
template.concat(template.capture
|
34
|
+
template.concat(template.capture(&block))
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def radio_button(
|
39
|
+
def radio_button(*, &block)
|
40
40
|
template.content_tag('div', class: 'radio') do
|
41
41
|
template.content_tag('label') do
|
42
42
|
template.concat(super)
|
43
|
-
template.concat(template.capture
|
43
|
+
template.concat(template.capture(&block))
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -5,34 +5,36 @@ module Lipstick
|
|
5
5
|
module FormHelper
|
6
6
|
include ActionView::Helpers::FormTagHelper
|
7
7
|
|
8
|
-
def field_block(html_opts = {})
|
8
|
+
def field_block(html_opts = {}, &block)
|
9
9
|
add_css_class(html_opts, 'form-group')
|
10
|
-
content_tag('div', html_opts)
|
10
|
+
content_tag('div', html_opts, &block)
|
11
11
|
end
|
12
12
|
|
13
|
-
|
13
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
14
|
+
def radio_button_tag(name, value, checked = false, options = {}, &block)
|
14
15
|
content_tag('div', class: 'radio') do
|
15
16
|
content_tag('label') do
|
16
17
|
concat(super)
|
17
|
-
concat(capture
|
18
|
+
concat(capture(&block))
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
22
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
21
23
|
|
22
|
-
def check_box_tag(
|
24
|
+
def check_box_tag(*, &block)
|
23
25
|
content_tag('div', class: 'checkbox') do
|
24
26
|
content_tag('label') do
|
25
27
|
concat(super)
|
26
|
-
concat(capture
|
28
|
+
concat(capture(&block))
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
33
|
alias orig_form_tag form_tag
|
32
34
|
|
33
|
-
def inline_form_tag(url_for_options = {}, options = {})
|
35
|
+
def inline_form_tag(url_for_options = {}, options = {}, &block)
|
34
36
|
add_css_class(options, 'form-inline')
|
35
|
-
form_tag(url_for_options, options)
|
37
|
+
form_tag(url_for_options, options, &block)
|
36
38
|
end
|
37
39
|
|
38
40
|
def search_form_tag(filter, url: nil,
|
@@ -111,7 +113,7 @@ module Lipstick
|
|
111
113
|
end
|
112
114
|
|
113
115
|
def delete_button_tag(url, text: true, **opts)
|
114
|
-
action = text
|
116
|
+
action = text.is_a?(String) ? text : 'Delete'
|
115
117
|
|
116
118
|
content_tag('div', class: 'btn-group') do
|
117
119
|
concat(delete_dropdown_opener(text && action, opts))
|
@@ -135,7 +137,7 @@ module Lipstick
|
|
135
137
|
# v.validate_field(:name, ...) # Validate the test_object[name] field
|
136
138
|
# end
|
137
139
|
# %>
|
138
|
-
def validate_form(selector, sym = nil)
|
140
|
+
def validate_form(selector, sym = nil, &block)
|
139
141
|
opts = {
|
140
142
|
type: 'application/vnd.aaf.lipstick.validations+json',
|
141
143
|
'data-target': selector,
|
@@ -143,7 +145,7 @@ module Lipstick
|
|
143
145
|
}
|
144
146
|
|
145
147
|
content_tag('script', opts) do
|
146
|
-
validation_json(sym)
|
148
|
+
validation_json(sym, &block).html_safe
|
147
149
|
end
|
148
150
|
end
|
149
151
|
|
@@ -42,9 +42,7 @@ module Lipstick
|
|
42
42
|
|
43
43
|
return validate_with_param(target, validation, true) if opts.empty?
|
44
44
|
|
45
|
-
if opts.keys == [:param]
|
46
|
-
return validate_with_param(target, validation, opts[:param])
|
47
|
-
end
|
45
|
+
return validate_with_param(target, validation, opts[:param]) if opts.keys == [:param]
|
48
46
|
|
49
47
|
add_rule(target, validation, opts)
|
50
48
|
end
|
@@ -10,11 +10,11 @@ module Lipstick
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def aaf_footer
|
13
|
+
def aaf_footer(&block)
|
14
14
|
content_tag('footer') do
|
15
15
|
content_tag('div', class: 'footer-content') do
|
16
16
|
concat(aaf_logo)
|
17
|
-
concat(capture
|
17
|
+
concat(capture(&block))
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module Lipstick
|
4
4
|
module Helpers
|
5
5
|
module NavHelper
|
6
|
-
def nav_bar
|
7
|
-
content_tag('nav', class: 'navbar shrink')
|
6
|
+
def nav_bar(&block)
|
7
|
+
content_tag('nav', class: 'navbar shrink', &block)
|
8
8
|
end
|
9
9
|
|
10
10
|
def nav_first_item(text, url)
|
@@ -14,10 +14,10 @@ module Lipstick
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def nav_collapsing_items
|
17
|
+
def nav_collapsing_items(&block)
|
18
18
|
attrs = { class: 'collapse navbar-collapse', id: 'aaf-nav-collapse' }
|
19
19
|
content_tag('div', attrs) do
|
20
|
-
content_tag('ul', class: 'nav navbar-nav')
|
20
|
+
content_tag('ul', class: 'nav navbar-nav', &block)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -25,13 +25,13 @@ module Lipstick
|
|
25
25
|
link_to request.query_parameters.merge(sort_by: param_name,
|
26
26
|
direction: opposite_direction) do
|
27
27
|
concat("#{name} ")
|
28
|
-
concat(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
)
|
28
|
+
concat(glyphicon(direction))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def glyphicon(direction)
|
33
|
+
content_tag('div', class: 'glyphicon') do
|
34
|
+
content_tag('div', nil, class: "glyphicon-chevron-#{icon(direction)}")
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
data/lib/lipstick/images.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rmagick'
|
4
|
-
|
5
3
|
module Lipstick
|
6
4
|
module Images
|
7
5
|
# Creates an AAF standard email banner, with three elements, positioned as
|
@@ -28,17 +26,24 @@ module Lipstick
|
|
28
26
|
#
|
29
27
|
# For image compositing, (x, y) is the position of the top-left corner.
|
30
28
|
class EmailBanner
|
31
|
-
def initialize(image:, title:, environment
|
29
|
+
def initialize(image:, title:, environment:,
|
30
|
+
background_color:, resize_to:)
|
31
|
+
require 'rmagick'
|
32
|
+
|
32
33
|
@title = title
|
33
34
|
@environment = environment
|
34
35
|
@image = image
|
36
|
+
@background_color = background_color
|
37
|
+
@resize_to = resize_to
|
35
38
|
end
|
36
39
|
|
37
40
|
def to_png
|
41
|
+
bgcolor = @background_color
|
42
|
+
|
38
43
|
canvas = Magick::ImageList.new
|
39
44
|
canvas.new_image(WIDTH, HEIGHT) do |f|
|
40
45
|
f.format = 'PNG'
|
41
|
-
f.background_color =
|
46
|
+
f.background_color = bgcolor
|
42
47
|
end
|
43
48
|
|
44
49
|
annotate_title(canvas)
|
@@ -90,7 +95,7 @@ module Lipstick
|
|
90
95
|
|
91
96
|
def logo
|
92
97
|
@logo ||= Magick::Image.read(@image.pathname.to_s).first
|
93
|
-
.resize_to_fill(
|
98
|
+
.resize_to_fill(@resize_to[0], @resize_to[1])
|
94
99
|
end
|
95
100
|
|
96
101
|
def gap
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lipstick
|
4
|
+
module Images
|
5
|
+
# Creates a logo-only email banner, with two elements.
|
6
|
+
#
|
7
|
+
# 1. Logo, centered vertically and horizontally within the image.
|
8
|
+
# 2. Environment string, stamped across the logo.
|
9
|
+
#
|
10
|
+
# The math here seemed like it would be a lot simpler than the EmailBanner
|
11
|
+
# class, but then I went and made it all confusing by bringing trigonometry
|
12
|
+
# into it. I promise there was a good reason for doing it.
|
13
|
+
class LogoOnlyEmailBanner
|
14
|
+
def initialize(image:, environment:, background_color:)
|
15
|
+
require 'rmagick'
|
16
|
+
|
17
|
+
@environment = environment.upcase
|
18
|
+
@image = image
|
19
|
+
@background_color = background_color
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_png
|
23
|
+
bgcolor = @background_color
|
24
|
+
|
25
|
+
canvas = Magick::ImageList.new
|
26
|
+
canvas.new_image(WIDTH, HEIGHT) do |f|
|
27
|
+
f.format = 'PNG'
|
28
|
+
f.background_color = bgcolor
|
29
|
+
end
|
30
|
+
|
31
|
+
canvas.composite!(logo, logo_x, logo_y, Magick::SrcOverCompositeOp)
|
32
|
+
|
33
|
+
annotate_environment(canvas)
|
34
|
+
|
35
|
+
canvas.to_blob
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
WIDTH = 600
|
41
|
+
HEIGHT = 150
|
42
|
+
MID_Y = HEIGHT / 2
|
43
|
+
ANGLE_DEGREES = 10
|
44
|
+
ANGLE_RADIANS = Math::PI * ANGLE_DEGREES / 180
|
45
|
+
private_constant :WIDTH, :HEIGHT, :MID_Y, :ANGLE_DEGREES, :ANGLE_RADIANS
|
46
|
+
|
47
|
+
def environment_format
|
48
|
+
@environment_format ||= Magick::Draw.new do |title|
|
49
|
+
title.font_family = 'ArialB'
|
50
|
+
title.font_weight = 900
|
51
|
+
title.pointsize = 36
|
52
|
+
title.gravity = Magick::ForgetGravity
|
53
|
+
title.fill = '#bc2028'
|
54
|
+
title.rotation = -1 * ANGLE_DEGREES
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def blank_environment?
|
59
|
+
!@environment&.present?
|
60
|
+
end
|
61
|
+
|
62
|
+
def annotate_environment(canvas)
|
63
|
+
return if blank_environment?
|
64
|
+
|
65
|
+
environment_format.annotate(canvas, 0, 0, env_x, env_y, @environment)
|
66
|
+
end
|
67
|
+
|
68
|
+
def logo
|
69
|
+
@logo ||= Magick::Image.read(@image.pathname.to_s).first
|
70
|
+
end
|
71
|
+
|
72
|
+
def gap
|
73
|
+
@gap ||= environment_format.get_type_metrics('AAF').width
|
74
|
+
end
|
75
|
+
|
76
|
+
def logo_w
|
77
|
+
logo.bounding_box.width
|
78
|
+
end
|
79
|
+
|
80
|
+
# x position to vertically center logo
|
81
|
+
def logo_x
|
82
|
+
((WIDTH - logo.bounding_box.width) / 2).round
|
83
|
+
end
|
84
|
+
|
85
|
+
# y position to vertically center logo
|
86
|
+
def logo_y
|
87
|
+
((HEIGHT - logo.bounding_box.height) / 2).round
|
88
|
+
end
|
89
|
+
|
90
|
+
def env_metrics
|
91
|
+
return OpenStruct.new(width: 0, height: 0) if blank_environment?
|
92
|
+
|
93
|
+
environment_format.get_type_metrics(@environment)
|
94
|
+
end
|
95
|
+
|
96
|
+
def env_x
|
97
|
+
m = env_metrics
|
98
|
+
|
99
|
+
# The horizontal width of the environment text is found by:
|
100
|
+
# w cos(0) + h sin(0)
|
101
|
+
#
|
102
|
+
# w = text width
|
103
|
+
# h = text ascent
|
104
|
+
# 0 = angle of text rotation
|
105
|
+
#
|
106
|
+
# Contrary to the description in `EmailBanner`, since we're upper
|
107
|
+
# casing the environment string here, we don't need to worry about text
|
108
|
+
# descent.
|
109
|
+
w = Math.cos(ANGLE_RADIANS) * m.width +
|
110
|
+
Math.sin(ANGLE_RADIANS) * m.ascent
|
111
|
+
|
112
|
+
# We center that the same as for `logo_x`
|
113
|
+
((WIDTH - w) / 2).round
|
114
|
+
end
|
115
|
+
|
116
|
+
def env_y
|
117
|
+
m = env_metrics
|
118
|
+
|
119
|
+
# The horizontal width of the environment text is found by:
|
120
|
+
# w sin(0) + h cos(0)
|
121
|
+
h = Math.sin(ANGLE_RADIANS) * m.width +
|
122
|
+
Math.cos(ANGLE_RADIANS) * m.ascent
|
123
|
+
|
124
|
+
# We use addition here instead of the usual subtraction, as the text
|
125
|
+
# moves in the upward direction from the position we set.
|
126
|
+
((HEIGHT + h) / 2).round
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -16,11 +16,28 @@ module Lipstick
|
|
16
16
|
end
|
17
17
|
# rubocop:enable Security/Eval
|
18
18
|
|
19
|
-
def email_banner(image: 'logo.png',
|
19
|
+
def email_banner(title:, environment:, image: 'logo.png', **kwargs)
|
20
20
|
@context.depend_on_asset(image)
|
21
21
|
asset = @context.environment.find_asset(image)
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
EmailBanner.new(
|
24
|
+
image: asset,
|
25
|
+
title: title,
|
26
|
+
environment: environment,
|
27
|
+
background_color: kwargs[:background_color] || '#2A3685',
|
28
|
+
resize_to: kwargs[:resize_to] || [78, 78]
|
29
|
+
).to_png
|
30
|
+
end
|
31
|
+
|
32
|
+
def logo_only_email_banner(environment:, image: 'logo.png', **kwargs)
|
33
|
+
@context.depend_on_asset(image)
|
34
|
+
asset = @context.environment.find_asset(image)
|
35
|
+
|
36
|
+
LogoOnlyEmailBanner.new(
|
37
|
+
image: asset,
|
38
|
+
environment: environment,
|
39
|
+
background_color: kwargs[:background_color] || '#2A3685'
|
40
|
+
).to_png
|
24
41
|
end
|
25
42
|
end
|
26
43
|
|
data/lib/lipstick/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aaf-lipstick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shaun Mangelsdorf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erubis
|
@@ -26,20 +26,6 @@ dependencies:
|
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: kramdown
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.5'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.5'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rails
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - ">="
|
@@ -53,7 +39,7 @@ dependencies:
|
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
42
|
+
name: rails
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - ">="
|
@@ -220,6 +206,20 @@ dependencies:
|
|
220
206
|
- - ">="
|
221
207
|
- !ruby/object:Gem::Version
|
222
208
|
version: '0'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: rmagick
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
223
|
- !ruby/object:Gem::Dependency
|
224
224
|
name: rspec-rails
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -252,22 +252,16 @@ dependencies:
|
|
252
252
|
name: sqlite3
|
253
253
|
requirement: !ruby/object:Gem::Requirement
|
254
254
|
requirements:
|
255
|
-
- - "
|
256
|
-
- !ruby/object:Gem::Version
|
257
|
-
version: '1.3'
|
258
|
-
- - "<"
|
255
|
+
- - ">="
|
259
256
|
- !ruby/object:Gem::Version
|
260
|
-
version: '
|
257
|
+
version: '0'
|
261
258
|
type: :development
|
262
259
|
prerelease: false
|
263
260
|
version_requirements: !ruby/object:Gem::Requirement
|
264
261
|
requirements:
|
265
|
-
- - "
|
266
|
-
- !ruby/object:Gem::Version
|
267
|
-
version: '1.3'
|
268
|
-
- - "<"
|
262
|
+
- - ">="
|
269
263
|
- !ruby/object:Gem::Version
|
270
|
-
version: '
|
264
|
+
version: '0'
|
271
265
|
- !ruby/object:Gem::Dependency
|
272
266
|
name: tilt
|
273
267
|
requirement: !ruby/object:Gem::Requirement
|
@@ -324,6 +318,7 @@ files:
|
|
324
318
|
- lib/lipstick/helpers/sortable_helper.rb
|
325
319
|
- lib/lipstick/images.rb
|
326
320
|
- lib/lipstick/images/email_banner.rb
|
321
|
+
- lib/lipstick/images/logo_only_email_banner.rb
|
327
322
|
- lib/lipstick/images/processor.rb
|
328
323
|
- lib/lipstick/sortable.rb
|
329
324
|
- lib/lipstick/version.rb
|
@@ -339,15 +334,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
339
334
|
requirements:
|
340
335
|
- - ">="
|
341
336
|
- !ruby/object:Gem::Version
|
342
|
-
version: '
|
337
|
+
version: '2.7'
|
343
338
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
344
339
|
requirements:
|
345
340
|
- - ">="
|
346
341
|
- !ruby/object:Gem::Version
|
347
342
|
version: '0'
|
348
343
|
requirements: []
|
349
|
-
|
350
|
-
rubygems_version: 2.5.2.3
|
344
|
+
rubygems_version: 3.1.2
|
351
345
|
signing_key:
|
352
346
|
specification_version: 4
|
353
347
|
summary: A gem for applying AAF branding to our services
|