populate-me 0.9.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1018ecfc599e93df910787d00774153225b3cd0712f4f457117e8fe24bd97367
4
- data.tar.gz: d6f45771022d5941be410d368933881689bfb9c9c5fe6f6ab4e76ce84f07a6b9
3
+ metadata.gz: b2770ba89bcfa96ad56baafdf141c67891317044051f44b117a8e6b438f7c432
4
+ data.tar.gz: f076278f23d91e5c59c141b39698c34a9083c5861ba01f41a3692d587bc0b73b
5
5
  SHA512:
6
- metadata.gz: d841176c180c4b9effb1b30d7a4e4643f4be01ad2854dfbd74fafffe0cd9dac7b1b7817d2e9e8810fa1ff5935418875abb0d4bff694e2fdb1497a54f37d65a4e
7
- data.tar.gz: 24dcc0e7770a04db79eaa342bc290539a3f11feca74ef2fe42d7be51c62eaab85c6cfaef9ba939298a0650a01b7dc765f433aa2303562663d5061d7f74c0e8e9
6
+ metadata.gz: f952a4160015147d54bab9a504f189613521e33342561e95ae33710cb2c3929a9a9512a96d6b0ed2812571a3faa7c972f3b550556884e44c9c0cd7df19922ed0
7
+ data.tar.gz: cd10b6ec3d88432f6255803150c6c1b129b0ffab6a6736d92243238976cfbf295413ea5a1cd9251029edfd798cdead3ac98fcbf51cd3f415a0011702ada41c5b
@@ -62,10 +62,10 @@ class PopulateMe::Admin < Sinatra::Base
62
62
  end
63
63
  items = current_level.map do |l|
64
64
  href = l[1].is_a?(String) ? l[1] : "#{request.script_name}/menu#{levels.map{|level|'/'+level}.join}/#{slugify(l[0])}"
65
- { title: l[0], href: href }
65
+ { title: l[0], href: href, new_page: (not href.start_with?('/')) }
66
66
  end
67
67
  if request.path_info=='/menu'
68
- items.push({title: '?', href: "#{request.script_name}/help"})
68
+ items.push({title: '?', href: "#{request.script_name}/help", new_page: false})
69
69
  end
70
70
  {
71
71
  template: 'template_menu',
@@ -140,10 +140,25 @@ button.admin-delete:focus, button.admin-delete-nested:focus, .handle-button:focu
140
140
  -ms-user-select: none;
141
141
  user-select: none;
142
142
  }
143
+ .documents.grid {
144
+ width: 90%; width: 90vw;
145
+ }
143
146
  .documents > li, .nested-documents > li {
144
147
  display: block;
145
148
  margin-bottom: 1em;
146
149
  }
150
+ .documents.grid > li {
151
+ display: inline-block;
152
+ vertical-align: top;
153
+ width: 200px;
154
+ margin-right: 1em;
155
+ }
156
+ .documents.grid > li > a {
157
+ word-break: break-word;
158
+ }
159
+ .documents.grid > li img {
160
+ width: 200px;
161
+ }
147
162
  .documents > li:hover, .nested-documents > li:hover {
148
163
  background-color: #eee8d5;
149
164
  outline: 0.5em solid #eee8d5;
@@ -195,6 +195,30 @@ PopulateMe.init_column = function(c) {
195
195
  // Init multiple select with asmSelect
196
196
  $('select[multiple]', c).asmSelect({ sortable: true, removeLabel: '&times;' });
197
197
 
198
+ // Select with preview
199
+ $('select:not([multiple])', c).change(function() {
200
+ var $this = $(this);
201
+ var container;
202
+ if ($this.data('preview-container')) {
203
+ container = $($this.data('preview-container'), c);
204
+ } else {
205
+ container = $this.next('.preview-container');
206
+ }
207
+ if (container.size() == 0) return;
208
+ var path = $this.find(':selected:first').data('preview');
209
+ if (path) {
210
+ var img = container.find('img:first');
211
+ if (img.size() < 1) {
212
+ img = $("<img src='' alt='Preview' title='Preview' width='250' />");
213
+ container.html(img);
214
+ }
215
+ img.attr('src', path);
216
+ } else {
217
+ container.html('');
218
+ }
219
+ });
220
+ $('option:selected[data-preview]').parent().change();
221
+
198
222
  // Polymorphic selector
199
223
  $('select.polymorphic_type_values').change(function() {
200
224
  var $this = $(this);
@@ -26,7 +26,7 @@
26
26
  <h1>{{page_title}}</h1>
27
27
  <ol class='menu'>
28
28
  {{#items}}
29
- <li><a href="{{href}}" class='column-push' title='Open'>{{title}}</a></li>
29
+ <li><a href="{{href}}" {{#new_page}}target='_blank'{{/new_page}}{{^new_page}}class='column-push'{{/new_page}} title='Open'>{{title}}</a></li>
30
30
  {{/items}}
31
31
  </ol>
32
32
  </script>
@@ -46,7 +46,7 @@
46
46
  {{/is_polymorphic}}
47
47
  <a href="<%= request.script_name %>/form/{{dasherized_class_name}}{{#new_data}}?{{new_data}}{{/new_data}}" class='column-push new-document-btn' title='Create'>+</a>
48
48
  </p>
49
- <ol class='documents' data-sort-field='{{sort_field}}' data-sort-url='<%= request.script_name %>/api/{{dasherized_class_name}}'>
49
+ <ol class='documents {{#grid_view}}grid{{/grid_view}}' data-sort-field='{{sort_field}}' data-sort-url='<%= request.script_name %>/api/{{dasherized_class_name}}'>
50
50
  {{#items}}{{#custom_partial_or_default}}template_document{{/custom_partial_or_default}}{{/items}}
51
51
  </ol>
52
52
  </script>
@@ -134,9 +134,10 @@
134
134
  {{/multiple}}
135
135
  <select name='{{input_name}}' {{#multiple}}multiple title='?'{{/multiple}}{{{build_input_attributes}}}>
136
136
  {{#select_options}}
137
- <option value='{{value}}' {{#selected}}selected{{/selected}}>{{description}}</option>
137
+ <option value='{{value}}' {{#selected}}selected{{/selected}} {{#preview_uri}}data-preview='{{preview_uri}}'{{/preview_uri}}>{{description}}</option>
138
138
  {{/select_options}}
139
139
  </select>
140
+ <div class='preview-container'></div>
140
141
  </script>
141
142
 
142
143
  <script id="template-attachment-field" type="x-tmpl-mustache">
@@ -76,11 +76,16 @@ module PopulateMe
76
76
  end
77
77
 
78
78
  def admin_get id
79
+ return self.admin_get_multiple(id) if id.is_a?(Array)
79
80
  self.cast do
80
- documents.find{|doc| doc[id_string_key]==id }
81
+ documents.find{|doc| doc[id_string_key] == id }
81
82
  end
82
83
  end
83
84
 
85
+ def admin_get_multiple ids, o={sort: nil}
86
+ self.admin_find(o.merge(query: {id_string_key => {'$in' => ids.uniq.compact}}))
87
+ end
88
+
84
89
  def admin_find o={}
85
90
  o[:query] ||= {}
86
91
  docs = self.cast{documents}.find_all do |d|
@@ -121,6 +126,7 @@ module PopulateMe
121
126
  end
122
127
  {
123
128
  template: 'template_list',
129
+ grid_view: self.settings[:grid_view]==true,
124
130
  page_title: self.to_s_short_plural,
125
131
  dasherized_class_name: WebUtils.dasherize_class_name(self.name),
126
132
  new_data: new_data,
@@ -160,13 +160,20 @@ module PopulateMe
160
160
 
161
161
  def to_select_options o={}
162
162
  proc do
163
- items = self.admin_find(query: (o[:query]||{}), fields: [self.id_string_key, self.label_field])
163
+ items = self.admin_find({
164
+ query: (o[:query]||{}),
165
+ fields: [self.id_string_key, self.label_field, self.admin_image_field].compact.uniq
166
+ })
164
167
  output = items.sort_by do |i|
165
168
  i.to_s.downcase
166
169
  end.map do |i|
167
- [i.to_s, i.id]
170
+ item = { description: i.to_s, value: i.id }
171
+ unless self.admin_image_field.nil?
172
+ item.merge! preview_uri: i.admin_image_url
173
+ end
174
+ item
168
175
  end
169
- output.unshift(['?','']) if o[:allow_empty]
176
+ output.unshift(description: '?', value: '') if o[:allow_empty]
170
177
  output
171
178
  end
172
179
  end
@@ -6,17 +6,43 @@ module PopulateMe
6
6
  class MissingMongoDBError < StandardError; end
7
7
 
8
8
  class Mongo < Document
9
+
10
+ self.settings.instance_eval do
11
+ def collection_name
12
+ puts 'yo'
13
+ if self[:collection_name].respond_to? :call
14
+ self[:collection_name].call
15
+ else
16
+ self[:collection_name]
17
+ end
18
+ end
19
+ end
9
20
 
10
21
  class << self
11
22
 
12
23
  def inherited sub
13
24
  super
14
- sub.set :collection_name, WebUtils.dasherize_class_name(sub.name)
25
+ # self.inherited is not useful anymore because we use ::collection_name
26
+ # so that the class name exist when this is run.
27
+ # Which is not the case with dynamically created classes.
28
+ #
29
+ # But we'll keep it for legacy code in the meantime.
30
+ # Decide if we want to keep it.
31
+ #
32
+ # If statment is here for dynamically created classes,
33
+ # because Class.new.name==nil and then it breaks (see tests).
34
+ unless sub.name.nil?
35
+ sub.set :collection_name, WebUtils.dasherize_class_name(sub.name)
36
+ end
37
+ end
38
+
39
+ def collection_name
40
+ self.settings.collection_name || WebUtils.dasherize_class_name(self.name)
15
41
  end
16
42
 
17
43
  def collection
18
44
  raise MissingMongoDBError, "Document class #{self.name} does not have a Mongo database." if settings.db.nil?
19
- settings.db[settings.collection_name]
45
+ settings.db[self.collection_name]
20
46
  end
21
47
 
22
48
  def set_id_field
@@ -62,11 +88,19 @@ module PopulateMe
62
88
  end
63
89
 
64
90
  def admin_get theid
91
+ return self.admin_get_multiple(theid) if theid.is_a?(Array)
65
92
  theid = string_or_object_id theid
66
93
  self.cast{ collection.find({id_string_key => theid}).first }
67
94
  end
68
95
  alias_method :[], :admin_get
69
96
 
97
+ def admin_get_multiple theids, o={sort: nil}
98
+ theids = theids.uniq.compact.map{|theid| string_or_object_id(theid) }
99
+ self.admin_find(o.merge({
100
+ query: {id_string_key => {'$in' => theids} }
101
+ }))
102
+ end
103
+
70
104
  def admin_find o={}
71
105
  query = o.delete(:query) || {}
72
106
  o[:sort] ||= @current_sort
@@ -1,4 +1,4 @@
1
1
  module PopulateMe
2
- VERSION = '0.9.1'
2
+ VERSION = '0.12.0'
3
3
  end
4
4
 
@@ -29,6 +29,6 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency 'rack-grid-serve', '~> 0.0.8'
30
30
  s.add_development_dependency 'aws-sdk-s3', '~> 1'
31
31
  s.add_development_dependency 'racksh', '~> 1.0'
32
- s.add_development_dependency 'rake', '~> 10.1'
32
+ s.add_development_dependency 'rake', '>= 12.3.3'
33
33
  end
34
34
 
@@ -124,6 +124,10 @@ describe PopulateMe::Admin do
124
124
 
125
125
  describe 'Handlers' do
126
126
 
127
+ let(:help_item) {
128
+ { 'title' => '?', 'href' => '/help', 'new_page' => false }
129
+ }
130
+
127
131
  describe '/menu' do
128
132
 
129
133
  describe 'when url is root' do
@@ -133,18 +137,22 @@ describe PopulateMe::Admin do
133
137
  assert_json last_response
134
138
  assert_for_view json, 'template_menu', 'Menu'
135
139
  expected_h = {
136
- 'title'=> 'Home Details', 'href'=> '/admin/form/home-details/0'
140
+ 'title' => 'Home Details',
141
+ 'href' => '/admin/form/home-details/0',
142
+ 'new_page' => false
137
143
  }
138
144
  assert_equal expected_h, json['items'][0]
139
145
  expected_h = {
140
- 'title'=> 'Project Page', 'href'=> '/menu/project-page'
146
+ 'title' => 'Project Page',
147
+ 'href' => '/menu/project-page',
148
+ 'new_page' => false
141
149
  }
142
150
  assert_equal expected_h, json['items'][1]
143
151
  end
144
152
  it 'Adds help link' do
145
153
  get '/menu'
146
154
  assert_equal 3, json['items'].size
147
- assert_equal({'title'=>'?', 'href'=>'/help'}, json['items'].last)
155
+ assert_equal(help_item, json['items'].last)
148
156
  end
149
157
  end
150
158
  describe 'when url is nested' do
@@ -155,13 +163,15 @@ describe PopulateMe::Admin do
155
163
  assert_for_view json, 'template_menu', 'Checks'
156
164
  assert_equal 2, json['items'].size
157
165
  expected_h = {
158
- 'title'=> 'Check 1', 'href'=> '/check/1'
166
+ 'title' => 'Check 1',
167
+ 'href' => '/check/1',
168
+ 'new_page' => false
159
169
  }
160
170
  assert_equal expected_h, json['items'][0]
161
171
  end
162
172
  it 'Does not add help link' do
163
173
  get '/menu/project-page/checks'
164
- refute_equal({'title'=>'?', 'href'=>'/help'}, json['items'].last)
174
+ refute_equal(help_item, json['items'].last)
165
175
  end
166
176
  end
167
177
 
@@ -11,6 +11,11 @@ class Outcasted < PopulateMe::Document
11
11
  {description: 'medium', value: 'm'},
12
12
  {description: 'large', value: 'l'}
13
13
  ]
14
+ field :availability, type: :select, select_options: [
15
+ {description: 'Available', value: 'yes', preview_uri: 'http://www.example.org/yes.jpg' },
16
+ {description: 'On offer', value: 'almost', preview_uri: 'http://www.example.org/almost.jpg' },
17
+ {description: 'Sold', value: 'no', preview_uri: 'http://www.example.org/no.jpg' }
18
+ ]
14
19
  field :tags, type: :select, select_options: ['art','sport','science'], multiple: true
15
20
  field :related_properties, type: :select, select_options: ['prop1','prop2','prop3'], multiple: true
16
21
  field :pdf, type: :attachment
@@ -98,6 +103,17 @@ describe PopulateMe::Document, 'Outcasting' do
98
103
  formated_options?(original, output)
99
104
  end
100
105
 
106
+ it 'Can have more fields when they are already formated' do
107
+ # Mainly for adding a preview_uri but also future tweaks
108
+ original = Outcasted.fields[:availability]
109
+ output = Outcasted.new.outcast(:availability, original, {input_name_prefix: 'data'})
110
+ assert(output[:select_options].all?{|o| o.key?(:preview_uri)})
111
+ last = output[:select_options].last
112
+ assert_equal 'Sold', last[:description]
113
+ assert_equal 'no', last[:value]
114
+ assert_equal 'http://www.example.org/no.jpg', last[:preview_uri]
115
+ end
116
+
101
117
  it 'Formats the options when it is a 2 strings array' do
102
118
  original = Outcasted.fields[:size].dup
103
119
  original[:select_options] = [
@@ -85,12 +85,22 @@ describe PopulateMe::Document, 'Schema' do
85
85
  label :slug
86
86
  end
87
87
 
88
+ class Selectpreviewable < PopulateMe::Document
89
+ set :default_attachment_class, PopulateMe::Attachment
90
+ field :name
91
+ field :img, type: :attachment, variations: [
92
+ PopulateMe::Variation.default
93
+ ]
94
+ end
95
+
88
96
  before do
89
97
  Selectoptionable.documents = []
90
98
  Selectoptionable.new(id: '1', name: 'Joe', slug: 'joe').save
91
99
  Selectoptionable.new(id: '2', name: 'William', slug: 'william').save
92
100
  Selectoptionable.new(id: '3', name: 'Jack', slug: 'jack').save
93
101
  Selectoptionable.new(id: '4', name: 'Averell', slug: 'averell').save
102
+ Selectpreviewable.documents = []
103
+ Selectpreviewable.new(id: '1', name: 'Project', img: 'project.jpg').save
94
104
  end
95
105
 
96
106
  after do
@@ -102,19 +112,27 @@ describe PopulateMe::Document, 'Schema' do
102
112
  assert output_proc.is_a?(Proc)
103
113
  output = output_proc.call
104
114
  assert_equal 4, output.size
105
- assert output.all?{|o| o.is_a?(Array) and o.size==2}
106
- assert_equal '1', output.find{|o|o[0]=='joe'}[1]
115
+ assert output.all?{|o| o.is_a?(Hash) and o.size==2}
116
+ assert_equal '1', output.find{|o|o.fetch(:description)=='joe'}.fetch(:value)
107
117
  end
108
118
 
109
119
  it 'Puts items in alphabetical order of their label' do
110
120
  output= Selectoptionable.to_select_options.call
111
- assert_equal ['averell', '4'], output[0]
121
+ assert_equal({description: 'averell', value: '4'}, output[0])
112
122
  end
113
123
 
114
124
  it 'Has an option for prepending empty choice' do
115
125
  output= Selectoptionable.to_select_options(allow_empty: true).call
116
- assert_equal ['?', ''], output[0]
117
- assert_equal ['averell', '4'], output[1]
126
+ assert_equal({description: '?', value: ''}, output[0])
127
+ assert_equal({description: 'averell', value: '4'}, output[1])
128
+ end
129
+
130
+ it 'Adds a :preview_uri when there is a thumbnail' do
131
+ output= Selectpreviewable.to_select_options.call
132
+ assert output[0].key?(:preview_uri)
133
+ assert_equal 'Project', output[0][:description]
134
+ assert_equal '1', output[0][:value]
135
+ assert_equal '/attachment/selectpreviewable/project.populate_me_thumb.jpg', output[0][:preview_uri]
118
136
  end
119
137
 
120
138
  end
@@ -65,14 +65,21 @@ describe 'PopulateMe::Mongo' do
65
65
  end
66
66
 
67
67
  it 'Should set DB collection to dasherized full class name by default' do
68
- assert_equal "cat-fish", CatFish.settings.collection_name
69
- assert_equal "paradise--cat-fish", Paradise::CatFish.settings.collection_name
68
+ assert_equal "cat-fish", CatFish.collection_name
69
+ assert_equal "paradise--cat-fish", Paradise::CatFish.collection_name
70
70
  end
71
71
 
72
72
  it 'Finds collection in DB' do
73
73
  assert_equal DB['cat-fish'].name, CatFish.collection.name
74
74
  end
75
75
 
76
+ it 'Should set DB and collection name even for dynamically created classes' do
77
+ # Happens when an included module automatically happens a class.
78
+ # e.g. Slides for a Slideshow
79
+ CatFish.const_set("Item", Class.new(CatFish.superclass))
80
+ assert_equal "cat-fish--item", CatFish::Item.collection.name
81
+ end
82
+
76
83
  end
77
84
 
78
85
  describe 'Low level CRUD' do
@@ -119,6 +126,19 @@ describe 'PopulateMe::Mongo' do
119
126
  assert_equal "regular", LowFish.admin_get(regular_fish_id).name
120
127
  end
121
128
 
129
+ it "Should get multiple items" do
130
+ # Order is not respected
131
+ alpha_id = LowFish.new(name: "alpha").perform_create
132
+ beta_id = LowFish.new(name: "beta").perform_create
133
+ gamma_id = LowFish.new(name: "gamma").perform_create
134
+ items = LowFish.admin_get([alpha_id, beta_id, nil, alpha_id])
135
+ assert items.is_a?(Array)
136
+ assert_equal 2, items.count
137
+ refute_nil items.find{|i| i.id == alpha_id}
138
+ refute_nil items.find{|i| i.id == beta_id}
139
+ assert_nil items.find{|i| i.id == gamma_id}
140
+ end
141
+
122
142
  it 'Should have the [] shortcut for admin_get' do
123
143
  LowFish.collection.insert_one(_id: 42, name: "H2G2")
124
144
  assert_equal LowFish[42], LowFish.admin_get(42)
@@ -131,7 +151,7 @@ describe 'PopulateMe::Mongo' do
131
151
  LowFish.collection.insert_one(_id: 40, name: "Bran")
132
152
  items = LowFish.admin_find
133
153
  assert items.is_a?(Array)
134
- assert 4, items.count
154
+ assert_equal 4, items.count
135
155
  assert_equal 10, items[0].id
136
156
  items = LowFish.admin_find query: {name: 'Bran'}
137
157
  assert items.is_a?(Array)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: populate-me
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mickael Riga
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-13 00:00:00.000000000 Z
11
+ date: 2020-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: web-utils
@@ -168,16 +168,16 @@ dependencies:
168
168
  name: rake
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - "~>"
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
- version: '10.1'
173
+ version: 12.3.3
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - "~>"
178
+ - - ">="
179
179
  - !ruby/object:Gem::Version
180
- version: '10.1'
180
+ version: 12.3.3
181
181
  description: PopulateMe is an admin system for managing structured content of web
182
182
  applications. It is built on top of the Sinatra framework, but can be used along
183
183
  any framework using Rack.
@@ -256,7 +256,7 @@ homepage: https://github.com/mig-hub/populate-me
256
256
  licenses:
257
257
  - MIT
258
258
  metadata: {}
259
- post_install_message:
259
+ post_install_message:
260
260
  rdoc_options: []
261
261
  require_paths:
262
262
  - lib
@@ -271,8 +271,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
271
  - !ruby/object:Gem::Version
272
272
  version: '0'
273
273
  requirements: []
274
- rubygems_version: 3.0.2
275
- signing_key:
274
+ rubygems_version: 3.0.3
275
+ signing_key:
276
276
  specification_version: 4
277
277
  summary: PopulateMe is an admin system for web applications.
278
278
  test_files: