intranet-pictures 2.1.0 → 3.0.0.rc1
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/lib/intranet/pictures/json_db_provider.rb +39 -27
- data/lib/intranet/pictures/responder.rb +45 -75
- data/lib/intranet/pictures/version.rb +1 -1
- data/lib/intranet/resources/haml/pictures_home.haml +18 -25
- data/lib/intranet/resources/locales/en.yml +2 -15
- data/lib/intranet/resources/locales/fr.yml +2 -15
- data/lib/intranet/resources/www/jpictures.js +156 -32
- data/lib/intranet/resources/www/photoswipe/photoswipe-dynamic-caption-plugin.css +8 -3
- data/lib/intranet/resources/www/photoswipe/photoswipe-dynamic-caption-plugin.esm.js +195 -173
- data/lib/intranet/resources/www/style.css +87 -13
- data/spec/intranet/pictures/json_db_provider_spec.rb +40 -23
- data/spec/intranet/pictures/responder_spec.rb +124 -177
- data/spec/intranet/pictures/sample-db.json +13 -9
- metadata +4 -5
- data/lib/intranet/resources/haml/pictures_browse.haml +0 -14
@@ -21,7 +21,8 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
21
21
|
@core = Intranet::Core.new(logger)
|
22
22
|
|
23
23
|
@provider = Intranet::Pictures::JsonDbProvider.new(File.join(__dir__, 'sample-db.json'))
|
24
|
-
|
24
|
+
defaults = { 'group_by' => 'location', 'sort_by' => 'datetime', 'sort_order' => 'desc' }
|
25
|
+
@responder = described_class.new(@provider, defaults)
|
25
26
|
@core.register_module(
|
26
27
|
@responder, ['pictures'], File.absolute_path('../../../lib/intranet/resources', __dir__)
|
27
28
|
)
|
@@ -29,14 +30,14 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
29
30
|
|
30
31
|
describe '#in_menu?' do
|
31
32
|
it 'should return the value provided at initialization' do
|
32
|
-
expect(described_class.new(nil,
|
33
|
-
expect(described_class.new(nil,
|
33
|
+
expect(described_class.new(nil, {}, false).in_menu?).to be false
|
34
|
+
expect(described_class.new(nil, {}, true).in_menu?).to be true
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
describe '#resources_dir' do
|
38
39
|
it 'should return the absolute path of the resources directory' do
|
39
|
-
expect(described_class.new(nil,
|
40
|
+
expect(described_class.new(nil, {}, false).resources_dir).to eql(
|
40
41
|
File.absolute_path('../../../lib/intranet/resources', __dir__)
|
41
42
|
)
|
42
43
|
end
|
@@ -44,35 +45,42 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
44
45
|
|
45
46
|
describe '#title' do
|
46
47
|
it 'should return the title of the webpage provided by the module' do
|
47
|
-
expect(@responder.title).to eql('
|
48
|
+
expect(@responder.title).to eql(I18n.t('pictures.menu'))
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
51
52
|
describe '#generate_page' do
|
52
53
|
context 'when asked for \'/index.html\'' do
|
53
|
-
it 'should return a partial HTML content
|
54
|
-
#
|
55
|
-
|
56
|
-
@responder.
|
57
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
54
|
+
it 'should return a partial HTML content with selected pictures grouped as requested' do
|
55
|
+
# No parameter in query: use default configuration provided at initialization & show all pictures
|
56
|
+
query = {}
|
57
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
58
58
|
expect(code).to eql(206)
|
59
59
|
expect(mime).to eql('text/html')
|
60
60
|
expect(content).to eql(
|
61
61
|
{
|
62
|
-
content: "<section>\n<h2
|
62
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
63
63
|
"<ul class='breadcrumb'>\n" \
|
64
64
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
65
65
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
66
|
-
"<li>My Gallery</li>\n" \
|
67
66
|
"</ul>\n\n" \
|
68
|
-
"<
|
67
|
+
"<h4>Tags</h4>\n" \
|
68
|
+
"<div id='tags'>\n" \
|
69
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
70
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
71
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
72
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
73
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
74
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
75
|
+
"</div>\n" \
|
76
|
+
"<h4>#{I18n.t('pictures.nav.location')}</h4>\n" \
|
69
77
|
"<ul class='groups'>\n" \
|
70
|
-
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
71
|
-
"<li title='Paris, France'>\n<a onclick='openImagesGallery("location=Paris, France&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
78
|
+
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
79
|
+
"<li title='Paris, France'>\n<a onclick='openImagesGallery("location=Paris, France&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
80
|
+
"<li title='Tokyo, Japan'>\n<a onclick='openImagesGallery("location=Tokyo, Japan&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
72
81
|
"</ul>\n" \
|
73
|
-
"<p class='see_more'>\n<a href='browse.html?group_by=location&sort_by=datetime&sort_order=desc'>#{I18n.t('pictures.see_more')}</a>\n</p>\n" \
|
74
82
|
"</section>\n",
|
75
|
-
title: '
|
83
|
+
title: I18n.t('pictures.menu'),
|
76
84
|
stylesheets: [
|
77
85
|
'design/style.css',
|
78
86
|
'design/photoswipe/photoswipe.css',
|
@@ -82,28 +90,34 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
82
90
|
}
|
83
91
|
)
|
84
92
|
|
85
|
-
#
|
86
|
-
|
87
|
-
@responder.
|
88
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
93
|
+
# Query overrides group_by field
|
94
|
+
query = { 'group_by' => 'author' }
|
95
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
89
96
|
expect(code).to eql(206)
|
90
97
|
expect(mime).to eql('text/html')
|
91
98
|
expect(content).to eql(
|
92
99
|
{
|
93
|
-
content: "<section>\n<h2
|
100
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
94
101
|
"<ul class='breadcrumb'>\n" \
|
95
102
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
96
103
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
97
|
-
"<li>My Gallery</li>\n" \
|
98
104
|
"</ul>\n\n" \
|
99
|
-
"<
|
105
|
+
"<h4>Tags</h4>\n" \
|
106
|
+
"<div id='tags'>\n" \
|
107
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
108
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
109
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
110
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
111
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
112
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
113
|
+
"</div>\n" \
|
114
|
+
"<h4>#{I18n.t('pictures.nav.author')}</h4>\n" \
|
100
115
|
"<ul class='groups'>\n" \
|
101
|
-
"<li title='
|
102
|
-
"<li title='
|
116
|
+
"<li title='Jane Doe'>\n<a onclick='openImagesGallery("author=Jane Doe&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=Jane Doe")'></div>\n<figcaption>\nJane Doe\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
117
|
+
"<li title='John Doe'>\n<a onclick='openImagesGallery("author=John Doe&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=John Doe")'></div>\n<figcaption>\nJohn Doe\n<br>\n<em>Best photographer ever</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
103
118
|
"</ul>\n" \
|
104
|
-
"<p class='see_more'>\n<a href='browse.html?group_by=location&sort_by=datetime'>#{I18n.t('pictures.see_more')}</a>\n</p>\n" \
|
105
119
|
"</section>\n",
|
106
|
-
title: '
|
120
|
+
title: I18n.t('pictures.menu'),
|
107
121
|
stylesheets: [
|
108
122
|
'design/style.css',
|
109
123
|
'design/photoswipe/photoswipe.css',
|
@@ -113,28 +127,34 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
113
127
|
}
|
114
128
|
)
|
115
129
|
|
116
|
-
#
|
117
|
-
|
118
|
-
@responder.
|
119
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
130
|
+
# Query overrides group_by field. This field is present for some pictures only.
|
131
|
+
query = { 'group_by' => 'camera' }
|
132
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
120
133
|
expect(code).to eql(206)
|
121
134
|
expect(mime).to eql('text/html')
|
122
135
|
expect(content).to eql(
|
123
136
|
{
|
124
|
-
content: "<section>\n<h2
|
137
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
125
138
|
"<ul class='breadcrumb'>\n" \
|
126
139
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
127
140
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
128
|
-
"<li>My Gallery</li>\n" \
|
129
141
|
"</ul>\n\n" \
|
130
|
-
"<
|
142
|
+
"<h4>Tags</h4>\n" \
|
143
|
+
"<div id='tags'>\n" \
|
144
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
145
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
146
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
147
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
148
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
149
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
150
|
+
"</div>\n" \
|
151
|
+
"<h4>#{I18n.t('pictures.nav.camera')}</h4>\n" \
|
131
152
|
"<ul class='groups'>\n" \
|
132
|
-
"<li title='
|
133
|
-
"<li title='
|
134
|
-
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
153
|
+
"<li title='Canon EOS 5D MARK IV'>\n<a onclick='openImagesGallery("camera=Canon EOS 5D MARK IV&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?camera=Canon EOS 5D MARK IV")'></div>\n<figcaption>\nCanon EOS 5D MARK IV\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
154
|
+
"<li title='Apple iPhone 11'>\n<a onclick='openImagesGallery("camera=Apple iPhone 11&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?camera=Apple iPhone 11")'></div>\n<figcaption>\nApple iPhone 11\n<br>\n<em>Best smartphone ever</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
135
155
|
"</ul>\n" \
|
136
156
|
"</section>\n",
|
137
|
-
title: '
|
157
|
+
title: I18n.t('pictures.menu'),
|
138
158
|
stylesheets: [
|
139
159
|
'design/style.css',
|
140
160
|
'design/photoswipe/photoswipe.css',
|
@@ -144,111 +164,30 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
144
164
|
}
|
145
165
|
)
|
146
166
|
|
147
|
-
#
|
148
|
-
|
149
|
-
@responder.
|
150
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
151
|
-
expect(code).to eql(404)
|
152
|
-
expect(mime).to be_empty
|
153
|
-
expect(content).to be_empty
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'should return a partial HTML content showing all groups according to configuration' do
|
157
|
-
# Nominal case without recents
|
158
|
-
home_groups = [{ 'group_by' => 'location', 'sort_by' => 'location',
|
159
|
-
'browse_group_by' => 'author' }]
|
160
|
-
@responder.instance_variable_set(:@home_groups, home_groups)
|
161
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
162
|
-
expect(code).to eql(206)
|
163
|
-
expect(mime).to eql('text/html')
|
164
|
-
expect(content).to eql(
|
165
|
-
{
|
166
|
-
content: "<section>\n<h2>My Gallery</h2>\n" \
|
167
|
-
"<ul class='breadcrumb'>\n" \
|
168
|
-
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
169
|
-
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
170
|
-
"<li>My Gallery</li>\n" \
|
171
|
-
"</ul>\n\n" \
|
172
|
-
"<h3>#{I18n.t('pictures.browse_by.location')}</h3>\n" \
|
173
|
-
"<ul class='groups wide'>\n" \
|
174
|
-
"<li title='New York, USA'>\n<a href='browse.html?group_by=author&location=New York, USA'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
175
|
-
"<li title='Paris, France'>\n<a href='browse.html?group_by=author&location=Paris, France'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
176
|
-
"<li title='Tokyo, Japan'>\n<a href='browse.html?group_by=author&location=Tokyo, Japan'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
177
|
-
"</ul>\n" \
|
178
|
-
"</section>\n",
|
179
|
-
title: 'My Gallery',
|
180
|
-
stylesheets: [
|
181
|
-
'design/style.css',
|
182
|
-
'design/photoswipe/photoswipe.css',
|
183
|
-
'design/photoswipe/photoswipe-dynamic-caption-plugin.css'
|
184
|
-
],
|
185
|
-
scripts: [{ src: 'design/jpictures.js', type: 'module' }]
|
186
|
-
}
|
187
|
-
)
|
188
|
-
|
189
|
-
# Nominal case with recents
|
190
|
-
recents = [{ 'group_by' => 'location', 'sort_by' => 'location', 'sort_order' => 'asc' }]
|
191
|
-
@responder.instance_variable_set(:@recents, recents)
|
192
|
-
home_groups = [{ 'group_by' => 'author', 'sort_by' => 'author', 'sort_order' => 'asc',
|
193
|
-
'browse_group_by' => 'location', 'browse_sort_by' => 'location', 'browse_sort_order' => 'desc' }]
|
194
|
-
@responder.instance_variable_set(:@home_groups, home_groups)
|
195
|
-
code, mime, content = @responder.generate_page('/index.html', {})
|
196
|
-
expect(code).to eql(206)
|
197
|
-
expect(mime).to eql('text/html')
|
198
|
-
expect(content).to eql(
|
199
|
-
{
|
200
|
-
content: "<section>\n<h2>My Gallery</h2>\n" \
|
201
|
-
"<ul class='breadcrumb'>\n" \
|
202
|
-
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
203
|
-
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
204
|
-
"<li>My Gallery</li>\n" \
|
205
|
-
"</ul>\n\n" \
|
206
|
-
"<h3>#{I18n.t('pictures.recents.location')}</h3>\n" \
|
207
|
-
"<ul class='groups'>\n" \
|
208
|
-
"<li title='New York, USA'>\n<a onclick='openImagesGallery("location=New York, USA&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=New York, USA")'></div>\n<figcaption>\nNew York, USA\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
209
|
-
"<li title='Paris, France'>\n<a onclick='openImagesGallery("location=Paris, France&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
210
|
-
"<li title='Tokyo, Japan'>\n<a onclick='openImagesGallery("location=Tokyo, Japan&sort_by=datetime");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
211
|
-
"</ul>\n" \
|
212
|
-
"<h3>#{I18n.t('pictures.browse_by.author')}</h3>\n" \
|
213
|
-
"<ul class='groups wide'>\n" \
|
214
|
-
"<li title='Jane Doe'>\n<a href='browse.html?group_by=location&sort_by=location&sort_order=desc&author=Jane Doe'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=Jane Doe")'></div>\n<figcaption>\nJane Doe\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
215
|
-
"<li title='John Doe'>\n<a href='browse.html?group_by=location&sort_by=location&sort_order=desc&author=John Doe'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?author=John Doe")'></div>\n<figcaption>\nJohn Doe\n<br>\n<em>Best photographer ever</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
216
|
-
"</ul>\n" \
|
217
|
-
"</section>\n",
|
218
|
-
title: 'My Gallery',
|
219
|
-
stylesheets: [
|
220
|
-
'design/style.css',
|
221
|
-
'design/photoswipe/photoswipe.css',
|
222
|
-
'design/photoswipe/photoswipe-dynamic-caption-plugin.css'
|
223
|
-
],
|
224
|
-
scripts: [{ src: 'design/jpictures.js', type: 'module' }]
|
225
|
-
}
|
226
|
-
)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
context 'when asked for \'/browse.html\'' do
|
231
|
-
it 'should return a partial HTML content with selected pictures grouped as requested' do
|
232
|
-
# No selector nor sort order
|
233
|
-
query = { 'group_by' => 'author' }
|
234
|
-
code, mime, content = @responder.generate_page('/browse.html', query)
|
167
|
+
# Query overrides defaults & specifies a valid selector
|
168
|
+
query = { 'group_by' => 'location', 'author' => 'John Doe', 'sort_by' => 'location', 'sort_order' => 'desc' }
|
169
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
235
170
|
expect(code).to eql(206)
|
236
171
|
expect(mime).to eql('text/html')
|
237
172
|
expect(content).to eql(
|
238
173
|
{
|
239
|
-
content: "<section>\n<h2
|
174
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
240
175
|
"<ul class='breadcrumb'>\n" \
|
241
176
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
242
177
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
243
|
-
"<li>\n<a href='index.html'>My Gallery</a>\n</li>\n" \
|
244
|
-
"<li>#{I18n.t('pictures.nav.author')}</li>\n" \
|
245
178
|
"</ul>\n\n" \
|
179
|
+
"<h4>Tags</h4>\n" \
|
180
|
+
"<div id='tags'>\n" \
|
181
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
182
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
183
|
+
"</div>\n" \
|
184
|
+
"<h4>#{I18n.t('pictures.nav.location')}</h4>\n" \
|
246
185
|
"<ul class='groups'>\n" \
|
247
|
-
"<li title='
|
248
|
-
"<li title='
|
186
|
+
"<li title='Tokyo, Japan'>\n<a onclick='openImagesGallery("author=John Doe&location=Tokyo, Japan&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Tokyo, Japan")'></div>\n<figcaption>\nTokyo, Japan\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
187
|
+
"<li title='Paris, France'>\n<a onclick='openImagesGallery("author=John Doe&location=Paris, France&sort_by=datetime&sort_order=asc");'>\n<figure>\n<div style='background-image: url("api/group_thumbnail?location=Paris, France")'></div>\n<figcaption>\nParis, France\n<br>\n<em>The City of Light</em>\n</figcaption>\n</figure>\n</a>\n</li>\n" \
|
249
188
|
"</ul>\n" \
|
250
189
|
"</section>\n",
|
251
|
-
title: '
|
190
|
+
title: I18n.t('pictures.menu'),
|
252
191
|
stylesheets: [
|
253
192
|
'design/style.css',
|
254
193
|
'design/photoswipe/photoswipe.css',
|
@@ -258,26 +197,24 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
258
197
|
}
|
259
198
|
)
|
260
199
|
|
261
|
-
#
|
262
|
-
query = { 'group_by' => 'location', '
|
263
|
-
code, mime, content = @responder.generate_page('/
|
200
|
+
# Invalid selector
|
201
|
+
query = { 'group_by' => 'location', 'foo' => 'bar' }
|
202
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
264
203
|
expect(code).to eql(206)
|
265
204
|
expect(mime).to eql('text/html')
|
266
205
|
expect(content).to eql(
|
267
206
|
{
|
268
|
-
content: "<section>\n<h2
|
207
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
269
208
|
"<ul class='breadcrumb'>\n" \
|
270
209
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
271
210
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
272
|
-
"<li>\n<a href='index.html'>My Gallery</a>\n</li>\n" \
|
273
|
-
"<li>#{I18n.t('pictures.nav.location')} (John Doe)</li>\n" \
|
274
211
|
"</ul>\n\n" \
|
275
|
-
"<
|
276
|
-
"<
|
277
|
-
"<
|
278
|
-
"</
|
212
|
+
"<h4>Tags</h4>\n" \
|
213
|
+
"<p>\n<em>#{I18n.t('pictures.no_result_found')}</em>\n</p>\n" \
|
214
|
+
"<h4>#{I18n.t('pictures.nav.location')}</h4>\n" \
|
215
|
+
"<p>\n<em>#{I18n.t('pictures.no_result_found')}</em>\n</p>\n" \
|
279
216
|
"</section>\n",
|
280
|
-
title: '
|
217
|
+
title: I18n.t('pictures.menu'),
|
281
218
|
stylesheets: [
|
282
219
|
'design/style.css',
|
283
220
|
'design/photoswipe/photoswipe.css',
|
@@ -287,23 +224,31 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
287
224
|
}
|
288
225
|
)
|
289
226
|
|
290
|
-
# Invalid
|
291
|
-
query = { 'group_by' => '
|
292
|
-
code, mime, content = @responder.generate_page('/
|
227
|
+
# Invalid grouping criteria
|
228
|
+
query = { 'group_by' => 'foo' }
|
229
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
293
230
|
expect(code).to eql(206)
|
294
231
|
expect(mime).to eql('text/html')
|
295
232
|
expect(content).to eql(
|
296
233
|
{
|
297
|
-
content: "<section>\n<h2
|
234
|
+
content: "<section>\n<h2>#{I18n.t('pictures.menu')}</h2>\n" \
|
298
235
|
"<ul class='breadcrumb'>\n" \
|
299
236
|
"<li>\n<a href='/index.html'>#{I18n.t('nav.home')}</a>\n</li>\n" \
|
300
237
|
"<li>#{I18n.t('pictures.menu')}</li>\n" \
|
301
|
-
"<li>\n<a href='index.html'>My Gallery</a>\n</li>\n" \
|
302
|
-
"<li>#{I18n.t('pictures.nav.location')} (bar)</li>\n" \
|
303
238
|
"</ul>\n\n" \
|
304
|
-
"<
|
239
|
+
"<h4>Tags</h4>\n" \
|
240
|
+
"<div id='tags'>\n" \
|
241
|
+
"<button class='tag' onclick='filterByTag("Cherry blossom");' type='button'>\nCherry blossom\n</button>\n" \
|
242
|
+
"<button class='tag' onclick='filterByTag("Louvre");' type='button'>\nLouvre\n</button>\n" \
|
243
|
+
"<button class='tag' onclick='filterByTag("MoMAK");' type='button'>\nMoMAK\n</button>\n" \
|
244
|
+
"<button class='tag' onclick='filterByTag("Modern art");' type='button'>\nModern art\n</button>\n" \
|
245
|
+
"<button class='tag' onclick='filterByTag("Pyramid");' type='button'>\nPyramid\n</button>\n" \
|
246
|
+
"<button class='tag' onclick='filterByTag("Urban photography");' type='button'>\nUrban photography\n</button>\n" \
|
247
|
+
"</div>\n" \
|
248
|
+
"<h4>#{I18n.t('pictures.nav.foo')}</h4>\n" \
|
249
|
+
"<p>\n<em>#{I18n.t('pictures.no_result_found')}</em>\n</p>\n" \
|
305
250
|
"</section>\n",
|
306
|
-
title: '
|
251
|
+
title: I18n.t('pictures.menu'),
|
307
252
|
stylesheets: [
|
308
253
|
'design/style.css',
|
309
254
|
'design/photoswipe/photoswipe.css',
|
@@ -313,16 +258,9 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
313
258
|
}
|
314
259
|
)
|
315
260
|
|
316
|
-
# Invalid grouping criteria
|
317
|
-
query = { 'group_by' => 'foo' }
|
318
|
-
code, mime, content = @responder.generate_page('/browse.html', query)
|
319
|
-
expect(code).to eql(404)
|
320
|
-
expect(mime).to be_empty
|
321
|
-
expect(content).to be_empty
|
322
|
-
|
323
261
|
# Invalid sorting criteria
|
324
262
|
query = { 'group_by' => 'location', 'sort_order' => 'foo' }
|
325
|
-
code, mime, content = @responder.generate_page('/
|
263
|
+
code, mime, content = @responder.generate_page('/index.html', query)
|
326
264
|
expect(code).to eql(404)
|
327
265
|
expect(mime).to be_empty
|
328
266
|
expect(content).to be_empty
|
@@ -339,7 +277,8 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
339
277
|
" viewer_close: '#{I18n.t('pictures.viewer.close')}',\n" \
|
340
278
|
" viewer_zoom: '#{I18n.t('pictures.viewer.zoom')}',\n" \
|
341
279
|
" viewer_previous: '#{I18n.t('pictures.viewer.previous')}',\n" \
|
342
|
-
" viewer_next: '#{I18n.t('pictures.viewer.next')}'
|
280
|
+
" viewer_next: '#{I18n.t('pictures.viewer.next')}',\n" \
|
281
|
+
" viewer_toggle_caption: '#{I18n.t('pictures.viewer.toggle_caption')}' };"
|
343
282
|
)
|
344
283
|
end
|
345
284
|
end
|
@@ -394,6 +333,13 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
394
333
|
expect(mime).to eql('application/json')
|
395
334
|
expect(content).to eql(''.to_json)
|
396
335
|
|
336
|
+
# Non-existing group
|
337
|
+
query = { 'flash' => 'true' }
|
338
|
+
code, mime, content = @responder.generate_page('/api/group_brief', query)
|
339
|
+
expect(code).to eql(404)
|
340
|
+
expect(mime).to be_empty
|
341
|
+
expect(content).to be_empty
|
342
|
+
|
397
343
|
# Invalid query
|
398
344
|
query = { 'location' => 'Tokyo, Japan', 'camera' => 'Canon EOS 5D MARK IV' }
|
399
345
|
code, mime, content = @responder.generate_page('/api/group_brief', query)
|
@@ -405,52 +351,53 @@ RSpec.describe Intranet::Pictures::Responder do
|
|
405
351
|
|
406
352
|
context 'when asked for \'/api/pictures\'' do
|
407
353
|
it 'should return a JSON representation of the selected pictures' do
|
408
|
-
# All pictures (no selector
|
354
|
+
# All pictures (no selector & default sort order)
|
409
355
|
code, mime, content = @responder.generate_page('/api/pictures', {})
|
410
356
|
expect(code).to eql(200)
|
411
357
|
expect(mime).to eql('application/json')
|
412
358
|
expect(content).to eql(
|
413
359
|
[
|
414
|
-
{ 'datetime' => '
|
415
|
-
{ 'datetime' => '2020:06:
|
416
|
-
{ 'datetime' => '2020:06:
|
417
|
-
{ 'datetime' => '
|
418
|
-
{ 'datetime' => '2019:07:22 09:
|
360
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' },
|
361
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] },
|
362
|
+
{ 'datetime' => '2020:06:19 07:51:05', 'flash' => 'false', 'author' => 'Jane Doe', 'location' => 'Tokyo, Japan', 'tags' => ['MoMAK', 'Modern art', 'Cherry blossom'] },
|
363
|
+
{ 'datetime' => '2019:07:22 09:45:17', 'author' => 'John Doe', 'location' => 'Tokyo, Japan' },
|
364
|
+
{ 'datetime' => '2019:07:22 09:41:31', 'author' => 'John Doe', 'location' => 'Paris, France', 'camera' => 'Apple iPhone 11', 'tags' => ['Modern art', 'Louvre'] }
|
419
365
|
].to_json
|
420
366
|
)
|
421
367
|
|
422
|
-
# Valid selector
|
423
|
-
query = { 'author' => 'Jane Doe', 'flash' => true }
|
368
|
+
# Valid selector & default sort order
|
369
|
+
query = { 'author' => 'Jane Doe', 'flash' => 'true' }
|
424
370
|
code, mime, content = @responder.generate_page('/api/pictures', query)
|
425
371
|
expect(code).to eql(200)
|
426
372
|
expect(mime).to eql('application/json')
|
427
373
|
expect(content).to eql(
|
428
374
|
[
|
429
|
-
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'New York, USA' },
|
430
|
-
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV' }
|
375
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' },
|
376
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] }
|
431
377
|
].to_json
|
432
378
|
)
|
433
379
|
|
434
380
|
# Valid selector, valid sort order
|
435
|
-
query = { 'author' => 'Jane Doe', '
|
381
|
+
query = { 'author' => 'Jane Doe', 'tags' => 'Urban photography', 'sort_by' => 'datetime',
|
382
|
+
'sort_order' => 'asc' }
|
436
383
|
code, mime, content = @responder.generate_page('/api/pictures', query)
|
437
384
|
expect(code).to eql(200)
|
438
385
|
expect(mime).to eql('application/json')
|
439
386
|
expect(content).to eql(
|
440
387
|
[
|
441
|
-
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV' },
|
442
|
-
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'New York, USA' }
|
388
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] },
|
389
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' }
|
443
390
|
].to_json
|
444
391
|
)
|
445
|
-
query = { 'author' => 'Jane Doe', 'flash' => true, 'sort_by' => 'location',
|
392
|
+
query = { 'author' => 'Jane Doe', 'flash' => 'true', 'sort_by' => 'location',
|
446
393
|
'sort_order' => 'desc' }
|
447
394
|
code, mime, content = @responder.generate_page('/api/pictures', query)
|
448
395
|
expect(code).to eql(200)
|
449
396
|
expect(mime).to eql('application/json')
|
450
397
|
expect(content).to eql(
|
451
398
|
[
|
452
|
-
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV' },
|
453
|
-
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => true, 'author' => 'Jane Doe', 'location' => 'New York, USA' }
|
399
|
+
{ 'datetime' => '2020:06:20 06:09:54', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'Paris, France', 'camera' => 'Canon EOS 5D MARK IV', 'tags' => ['Louvre', 'Pyramid', 'Urban photography'] },
|
400
|
+
{ 'datetime' => '2020:06:20 18:14:09', 'flash' => 'true', 'author' => 'Jane Doe', 'location' => 'New York, USA', 'tags' => 'Urban photography' }
|
454
401
|
].to_json
|
455
402
|
)
|
456
403
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
{
|
2
|
-
"title": "My Gallery",
|
3
2
|
"groups": {
|
4
3
|
"author": [
|
5
4
|
{
|
@@ -27,7 +26,8 @@
|
|
27
26
|
],
|
28
27
|
"camera": [
|
29
28
|
{
|
30
|
-
"id": "Apple iPhone 11"
|
29
|
+
"id": "Apple iPhone 11",
|
30
|
+
"brief": "Best smartphone ever"
|
31
31
|
},
|
32
32
|
{
|
33
33
|
"id": "Canon EOS 5D MARK IV"
|
@@ -40,29 +40,33 @@
|
|
40
40
|
"datetime": "2019:07:22 09:41:31",
|
41
41
|
"author": "John Doe",
|
42
42
|
"location": "Paris, France",
|
43
|
-
"camera": "Apple iPhone 11"
|
43
|
+
"camera": "Apple iPhone 11",
|
44
|
+
"tags": [ "Modern art", "Louvre" ]
|
44
45
|
},
|
45
46
|
{
|
46
47
|
"uri": "./alpha.png",
|
47
48
|
"datetime": "2020:06:19 07:51:05",
|
48
|
-
"flash": false,
|
49
|
+
"flash": "false",
|
49
50
|
"author": "Jane Doe",
|
50
|
-
"location": "Tokyo, Japan"
|
51
|
+
"location": "Tokyo, Japan",
|
52
|
+
"tags": [ "MoMAK", "Modern art", "Cherry blossom" ]
|
51
53
|
},
|
52
54
|
{
|
53
55
|
"uri": "pic3.jpg",
|
54
56
|
"datetime": "2020:06:20 18:14:09",
|
55
|
-
"flash": true,
|
57
|
+
"flash": "true",
|
56
58
|
"author": "Jane Doe",
|
57
|
-
"location": "New York, USA"
|
59
|
+
"location": "New York, USA",
|
60
|
+
"tags": "Urban photography"
|
58
61
|
},
|
59
62
|
{
|
60
63
|
"uri": "sample-db.json",
|
61
64
|
"datetime": "2020:06:20 06:09:54",
|
62
|
-
"flash": true,
|
65
|
+
"flash": "true",
|
63
66
|
"author": "Jane Doe",
|
64
67
|
"location": "Paris, France",
|
65
|
-
"camera": "Canon EOS 5D MARK IV"
|
68
|
+
"camera": "Canon EOS 5D MARK IV",
|
69
|
+
"tags": [ "Louvre", "Pyramid", "Urban photography" ]
|
66
70
|
},
|
67
71
|
{
|
68
72
|
"datetime": "2019:07:22 09:45:17",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: intranet-pictures
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ebling Mis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: intranet-core
|
@@ -53,7 +53,6 @@ files:
|
|
53
53
|
- lib/intranet/pictures/json_db_provider.rb
|
54
54
|
- lib/intranet/pictures/responder.rb
|
55
55
|
- lib/intranet/pictures/version.rb
|
56
|
-
- lib/intranet/resources/haml/pictures_browse.haml
|
57
56
|
- lib/intranet/resources/haml/pictures_home.haml
|
58
57
|
- lib/intranet/resources/locales/en.yml
|
59
58
|
- lib/intranet/resources/locales/fr.yml
|
@@ -89,9 +88,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
89
88
|
version: '3.0'
|
90
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
90
|
requirements:
|
92
|
-
- - "
|
91
|
+
- - ">"
|
93
92
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
93
|
+
version: 1.3.1
|
95
94
|
requirements: []
|
96
95
|
rubygems_version: 3.3.15
|
97
96
|
signing_key:
|