populate-me 0.11.0 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: faa748585887ab4c87b9a96b0fcbc1cb819933840e5ed916a3455ea677c10ada
4
- data.tar.gz: '0548e4f13d04c8f9a5375029fc11e6cfdd00b7759b2a6b5ba171151640ee5159'
3
+ metadata.gz: 0e07006c1f567c3309a537233c482114dd0536b783c6e82b1cafcf7d5c53fa12
4
+ data.tar.gz: f36fc1cb24ac5b59ea7090c6ffc5c425d437ef95e36f528fb012bb721472d185
5
5
  SHA512:
6
- metadata.gz: 3244bbeb680e2d0ffea098719cc228623115666b498330651563672455c2495cfd3955270943f4b0020fc54780e876dd644a9025b0ff7f325eb016586f75cc8f
7
- data.tar.gz: 3489e40c4e16e1b75c005d09937c535de3eef8d52edf8de9b1aa54a43d71a7a8304a7e80ebaaec2486da4b344b28752b1451f82e224f2014cc00d74a0e417118
6
+ metadata.gz: 6e53cfb5b625bbb4835cb5ba5fa5e404dfaac6e23eb607d5f981ff6c60ed67f2939d0dd4a288476ce1bd486804264c6516b2a79439c6ba302a080c2a0270dd2c
7
+ data.tar.gz: 2ca83c16c743176e272793b3d411887b7b3ea9a7f4d01ba71cad0fcd2e1417423d526116d7f09ef4f24b4fc85c54b0c9399cb6a6445fb4c074d1ac09892fa1af
@@ -67,6 +67,7 @@ class PopulateMe::Admin < Sinatra::Base
67
67
  if request.path_info=='/menu'
68
68
  items.push({title: '?', href: "#{request.script_name}/help", new_page: false})
69
69
  end
70
+ content_type :json
70
71
  {
71
72
  template: 'template_menu',
72
73
  page_title: page_title,
@@ -76,6 +77,7 @@ class PopulateMe::Admin < Sinatra::Base
76
77
 
77
78
  get '/list/:class_name' do
78
79
  @model_class = resolve_model_class params[:class_name]
80
+ content_type :json
79
81
  @model_class.to_admin_list(request: request, params: params).to_json
80
82
  end
81
83
 
@@ -87,6 +89,7 @@ class PopulateMe::Admin < Sinatra::Base
87
89
  else
88
90
  @model_instance = resolve_model_instance @model_class, params[:id]
89
91
  end
92
+ content_type :json
90
93
  @model_instance.to_admin_form(
91
94
  request: request,
92
95
  params: params,
@@ -102,6 +105,7 @@ class PopulateMe::Admin < Sinatra::Base
102
105
 
103
106
  not_found do
104
107
  response.headers['X-Cascade'] = 'pass'
108
+ content_type :json
105
109
  {'success'=>false,'message'=>'Not Found'}.to_json
106
110
  end
107
111
 
@@ -109,6 +113,7 @@ class PopulateMe::Admin < Sinatra::Base
109
113
  puts
110
114
  puts env['sinatra.error'].inspect
111
115
  puts
116
+ content_type :json
112
117
  {'success'=>false,'message'=>env['sinatra.error'].message}.to_json
113
118
  end
114
119
 
@@ -184,16 +184,20 @@ form {
184
184
  margin-bottom: 1em;
185
185
  }
186
186
 
187
- input[type=text], input[type=email],
187
+ input[type=text], input[type=email], input[type=search],
188
188
  textarea {
189
189
  border: 0px;
190
190
  color: #839496;
191
- background: #ffffff;
191
+ background-color: #ffffff;
192
192
  width: 400px;
193
193
  padding: 0.5em;
194
194
  font-size: 1em;
195
+ outline: 0;
196
+ }
197
+ input[type=text].search-items {
198
+ border-radius: 1em;
195
199
  }
196
- input[type=text]:focus, input[type=email]:focus,
200
+ input[type=text]:focus, input[type=email]:focus, input[type=email]:focus,
197
201
  textarea:focus {
198
202
  /* color: #002b36; */
199
203
  }
@@ -45,14 +45,18 @@
45
45
  root.busy = false;
46
46
  root.on('push.columnav', function(e,data,cb) {
47
47
  var $data = $("<li class='"+settings.column_class+"'>"+data+"</li>");
48
- root.append($data);
49
- new_column($data, root);
50
- var cb_object = {event:e,column:$data,container:root,settings:settings};
51
- root.animate({scrollLeft: root.width()},function(){
48
+ async function push_callback_stack() {
49
+ await root.append($data);
50
+ await new_column($data, root);
51
+ var cb_object = {event:e,column:$data,container:root,settings:settings};
52
+ await settings.on_push(cb_object);
53
+ if (typeof cb == 'function') await cb(cb_object);
52
54
  root.busy = false;
53
- settings.on_push(cb_object);
54
- if (typeof cb == 'function') cb(cb_object);
55
- });
55
+ root.find('> li:last-child').get(0).scrollIntoView({
56
+ behavior: 'smooth', inline: 'start'
57
+ });
58
+ }
59
+ push_callback_stack();
56
60
  });
57
61
  root.on('getandpush.columnav', function(e,url,cb) {
58
62
  $.get(url, function(data) {
@@ -63,7 +67,7 @@
63
67
  });
64
68
  });
65
69
  root.on('pop.columnav', function(e,removable,cb) {
66
- removable = removable || root.children().last();
70
+ removable = removable || root.find('> li:last-child');
67
71
  removable.css({visibility:'hidden'})
68
72
  .animate({width:0},function(){
69
73
  // Trick to make sure it runs only once
@@ -94,12 +94,24 @@ PopulateMe.make_sortable = function(selector,context) {
94
94
  });
95
95
  };
96
96
 
97
+ // Copy and restore column search.
98
+ // Used when saving pops the columns.
99
+ PopulateMe.copy_column_search = function(column) {
100
+ return column.find('.search-items').val();
101
+ };
102
+ PopulateMe.restore_column_search = function(column, value) {
103
+ if (value !== '' && column.data('qs')) {
104
+ column.find('.search-items').val(value);
105
+ column.data('qs').search(value);
106
+ }
107
+ };
108
+
97
109
  // Scroll to an element, possibly in a specific column.
98
110
  PopulateMe.scroll_to = function(el, column) {
99
111
  if (!column) {
100
112
  column = el.closest('.column');
101
113
  }
102
- column.animate({scrollTop: el.position().top});
114
+ el.get(0).scrollIntoView({ behavior: 'smooth'});
103
115
  };
104
116
 
105
117
  // Mark errors for report after form validation.
@@ -162,33 +174,54 @@ PopulateMe.jsValidationsPassed = function(context) {
162
174
  // in case you have things to put in your custom javascript.
163
175
  PopulateMe.init_column = function(c) {
164
176
 
177
+ var documents = $('.documents', c);
178
+
165
179
  // Sort list item
166
- PopulateMe.make_sortable('.documents',c).bind('sortupdate', function(e, ui) {
167
- var list = $(ui.item).closest('.documents');
168
- var ids = list.children().map(function() {
169
- return $(this).data().id;
170
- }).get();
171
- $.ajax({
172
- url: list.data().sortUrl,
173
- type: 'put',
174
- data: {
175
- action: 'sort',
176
- field: list.data().sortField,
177
- ids: ids
178
- }
180
+ if (documents.data('sort-field') !== '') {
181
+ PopulateMe.make_sortable(documents).bind('sortupdate', function(e, ui) {
182
+ var list = $(ui.item).closest('.documents');
183
+ var ids = list.children().map(function() {
184
+ return $(this).data().id;
185
+ }).get();
186
+ $.ajax({
187
+ url: list.data().sortUrl,
188
+ type: 'put',
189
+ data: {
190
+ action: 'sort',
191
+ field: list.data().sortField,
192
+ ids: ids
193
+ }
194
+ });
195
+ /*
196
+ ui.item contains the current dragged element.
197
+ ui.item.index() contains the new index of the dragged element
198
+ ui.oldindex contains the old index of the dragged element
199
+ ui.startparent contains the element that the dragged item comes from
200
+ ui.endparent contains the element that the dragged item was added to
201
+ */
179
202
  });
180
- /*
181
- ui.item contains the current dragged element.
182
- ui.item.index() contains the new index of the dragged element
183
- ui.oldindex contains the old index of the dragged element
184
- ui.startparent contains the element that the dragged item comes from
185
- ui.endparent contains the element that the dragged item was added to
186
- */
187
- });
203
+ }
188
204
 
189
205
  // Sort nested documents
190
206
  PopulateMe.make_sortable('.nested-documents',c);
191
207
 
208
+ $('.search-items', c).each(function() {
209
+ var field = $(this)
210
+ var qs = field.quicksearch($('.admin-list-item', c), {
211
+ selector: '.item-title',
212
+ onAfter: function() {
213
+ if (documents.is('.ui-sortable')) {
214
+ if (field.val() == '') {
215
+ documents.sortable('enable');
216
+ } else {
217
+ documents.sortable('disable');
218
+ }
219
+ }
220
+ }
221
+ });
222
+ c.data('qs', qs);
223
+ });
224
+
192
225
  // Init textareas
193
226
  $('textarea',c).trigger('input');
194
227
 
@@ -285,11 +318,14 @@ $(function() {
285
318
  contentType: false,
286
319
  success: function(res) {
287
320
  if (res.success==true) {
288
- var reloader = PopulateMe.finder.find('> li:nth-last-child(3) .selected')
321
+ var reloader = PopulateMe.finder.find('> li:nth-last-child(3) .selected');
289
322
  if (reloader.size()>0) {
323
+ var reloadee = PopulateMe.finder.find('> li:nth-last-child(2)');
324
+ var current_search = PopulateMe.copy_column_search(reloadee);
290
325
  reloader.trigger('click.columnav',[function(cb_object) {
291
- var target = $('[data-id='+res.data.id+']', cb_object.column);
326
+ var target = $('[data-id='+res.data._id+']', cb_object.column);
292
327
  if (target.size()>0) {
328
+ PopulateMe.restore_column_search(cb_object.column, current_search);
293
329
  PopulateMe.scroll_to(target, cb_object.column);
294
330
  }
295
331
  }]);
@@ -377,6 +413,8 @@ $(function() {
377
413
  process_data: function(data) {
378
414
  if (typeof data == 'object') {
379
415
  return PopulateMe.mustache_render(data);
416
+ } else if (typeof data == 'string' && data[0] == '{') {
417
+ return PopulateMe.mustache_render(JSON.parse(data));
380
418
  } else {
381
419
  return data;
382
420
  }
@@ -0,0 +1 @@
1
+ (function($,window,document,undefined){$.fn.quicksearch=function(target,opt){var timeout,cache,rowcache,jq_results,val="",e=this,options=$.extend({delay:100,selector:null,stripeRows:null,loader:null,noResults:"",matchedResultsCount:0,bind:"keyup",onBefore:function(){return},onAfter:function(){return},show:function(){this.style.display=""},hide:function(){this.style.display="none"},prepareQuery:function(val){return val.toLowerCase().split(" ")},testQuery:function(query,txt,_row){for(var i=0;i<query.length;i+=1){if(txt.indexOf(query[i])===-1){return false}}return true}},opt);this.go=function(){var i=0,numMatchedRows=0,noresults=true,query=options.prepareQuery(val),val_empty=val.replace(" ","").length===0;for(var i=0,len=rowcache.length;i<len;i++){if(val_empty||options.testQuery(query,cache[i],rowcache[i])){options.show.apply(rowcache[i]);noresults=false;numMatchedRows++}else{options.hide.apply(rowcache[i])}}if(noresults){this.results(false)}else{this.results(true);this.stripe()}this.matchedResultsCount=numMatchedRows;this.loader(false);options.onAfter();return this};this.search=function(submittedVal){val=submittedVal;e.trigger()};this.currentMatchedResults=function(){return this.matchedResultsCount};this.stripe=function(){if(typeof options.stripeRows==="object"&&options.stripeRows!==null){var joined=options.stripeRows.join(" ");var stripeRows_length=options.stripeRows.length;jq_results.not(":hidden").each(function(i){$(this).removeClass(joined).addClass(options.stripeRows[i%stripeRows_length])})}return this};this.strip_html=function(input){var output=input.replace(new RegExp("<[^<]+>","g"),"");output=$.trim(output.toLowerCase());return output};this.results=function(bool){if(typeof options.noResults==="string"&&options.noResults!==""){if(bool){$(options.noResults).hide()}else{$(options.noResults).show()}}return this};this.loader=function(bool){if(typeof options.loader==="string"&&options.loader!==""){bool?$(options.loader).show():$(options.loader).hide()}return this};this.cache=function(){jq_results=$(target);if(typeof options.noResults==="string"&&options.noResults!==""){jq_results=jq_results.not(options.noResults)}var t=typeof options.selector==="string"?jq_results.find(options.selector):$(target).not(options.noResults);cache=t.map(function(){return e.strip_html(this.innerHTML)});rowcache=jq_results.map(function(){return this});val=val||this.val()||"";return this.go()};this.trigger=function(){this.loader(true);options.onBefore();window.clearTimeout(timeout);timeout=window.setTimeout(function(){e.go()},options.delay);return this};this.cache();this.results(true);this.stripe();this.loader(false);return this.each(function(){$(this).on(options.bind,function(){val=$(this).val();e.trigger()})})}})(jQuery,this,document);
@@ -46,6 +46,9 @@
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
+ <form class='form-search-items'>
50
+ <input type='text' class='search-items' placeholder='Search'>
51
+ </form>
49
52
  <ol class='documents {{#grid_view}}grid{{/grid_view}}' data-sort-field='{{sort_field}}' data-sort-url='<%= request.script_name %>/api/{{dasherized_class_name}}'>
50
53
  {{#items}}{{#custom_partial_or_default}}template_document{{/custom_partial_or_default}}{{/items}}
51
54
  </ol>
@@ -57,7 +60,7 @@
57
60
  <button type='button' class='admin-delete' title='Delete' value='<%= request.script_name %>/api/{{admin_url}}'>&times;</button>
58
61
  </header>
59
62
  <a href="<%= request.script_name %>/form/{{admin_url}}" class='column-push' title='Edit'>
60
- {{title}}
63
+ <span class='item-title'>{{title}}</span>
61
64
  {{#image_url}}
62
65
  <br />
63
66
  <img src='{{image_url}}{{cache_buster}}' alt='{{title}}' width='300' />
@@ -142,7 +145,7 @@
142
145
 
143
146
  <script id="template-attachment-field" type="x-tmpl-mustache">
144
147
  {{#url}}
145
- <img src='{{url}}{{cache_buster}}' alt='Preview' width='150' />
148
+ <img src='{{url}}{{cache_buster}}' alt='Preview' width='150' onerror="this.src='<%= request.script_name %>/__assets__/img/file.png'; this.onerror=null;" />
146
149
  <button class='attachment-deleter'>x</button>
147
150
  <br />
148
151
  {{/url}}
@@ -176,6 +179,7 @@
176
179
  <script src="<%= request.script_name %>/__assets__/js/columnav.js" type="text/javascript" charset="utf-8"></script>
177
180
  <%# <script src="<%= request.script_name %1>/__assets__/js/sortable.js" type="text/javascript" charset="utf-8"></script> %>
178
181
  <script src="<%= request.script_name %>/__assets__/js/asmselect.js" type="text/javascript" charset="utf-8"></script>
182
+ <script src="<%= request.script_name %>/__assets__/js/quicksearch.js" type="text/javascript" charset="utf-8"></script>
179
183
  <script type="text/javascript">
180
184
  window.admin_path = "<%= request.script_name %>";
181
185
  window.index_path = "<%= settings.index_path %>";
@@ -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|
@@ -119,6 +124,7 @@ module PopulateMe
119
124
  end
120
125
  new_data = Rack::Utils.build_nested_query(data: o[:params][:filter])
121
126
  end
127
+ items = self.admin_find(query: query)
122
128
  {
123
129
  template: 'template_list',
124
130
  grid_view: self.settings[:grid_view]==true,
@@ -130,7 +136,7 @@ module PopulateMe
130
136
  sort_field: self.sort_field_for(o),
131
137
  # 'command_plus'=> !self.populate_config[:no_plus],
132
138
  # 'command_search'=> !self.populate_config[:no_search],
133
- items: self.admin_find(query: query).map do |d|
139
+ items: items.map do |d|
134
140
  d.to_admin_list_item(o)
135
141
  end
136
142
  }
@@ -88,11 +88,19 @@ module PopulateMe
88
88
  end
89
89
 
90
90
  def admin_get theid
91
+ return self.admin_get_multiple(theid) if theid.is_a?(Array)
91
92
  theid = string_or_object_id theid
92
93
  self.cast{ collection.find({id_string_key => theid}).first }
93
94
  end
94
95
  alias_method :[], :admin_get
95
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
+
96
104
  def admin_find o={}
97
105
  query = o.delete(:query) || {}
98
106
  o[:sort] ||= @current_sort
@@ -27,7 +27,7 @@ module PopulateMe
27
27
  end
28
28
 
29
29
  def default
30
- self.new_image_magick_job(:populate_me_thumb, :jpg, "-flatten -resize '400x225^' -gravity center -extent 400x225")
30
+ self.new_image_magick_job(:populate_me_thumb, :jpg, "-flatten -resize '400x230' -gravity center -extent 400x230")
31
31
  end
32
32
 
33
33
  end
@@ -1,4 +1,4 @@
1
1
  module PopulateMe
2
- VERSION = '0.11.0'
2
+ VERSION = '0.14.0'
3
3
  end
4
4
 
@@ -1,5 +1,6 @@
1
1
  require 'helper'
2
2
  require 'populate_me/document'
3
+ require 'populate_me/attachment'
3
4
 
4
5
  describe PopulateMe::Document, 'Schema' do
5
6
 
data/test/test_mongo.rb CHANGED
@@ -126,6 +126,19 @@ describe 'PopulateMe::Mongo' do
126
126
  assert_equal "regular", LowFish.admin_get(regular_fish_id).name
127
127
  end
128
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
+
129
142
  it 'Should have the [] shortcut for admin_get' do
130
143
  LowFish.collection.insert_one(_id: 42, name: "H2G2")
131
144
  assert_equal LowFish[42], LowFish.admin_get(42)
@@ -138,7 +151,7 @@ describe 'PopulateMe::Mongo' do
138
151
  LowFish.collection.insert_one(_id: 40, name: "Bran")
139
152
  items = LowFish.admin_find
140
153
  assert items.is_a?(Array)
141
- assert 4, items.count
154
+ assert_equal 4, items.count
142
155
  assert_equal 10, items[0].id
143
156
  items = LowFish.admin_find query: {name: 'Bran'}
144
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.11.0
4
+ version: 0.14.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: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2021-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: web-utils
@@ -198,6 +198,7 @@ files:
198
198
  - lib/populate_me/admin/__assets__/css/asmselect.css
199
199
  - lib/populate_me/admin/__assets__/css/jquery-ui.min.css
200
200
  - lib/populate_me/admin/__assets__/css/main.css
201
+ - lib/populate_me/admin/__assets__/img/file.png
201
202
  - lib/populate_me/admin/__assets__/img/help/children.png
202
203
  - lib/populate_me/admin/__assets__/img/help/create.png
203
204
  - lib/populate_me/admin/__assets__/img/help/delete.png
@@ -216,6 +217,7 @@ files:
216
217
  - lib/populate_me/admin/__assets__/js/jquery-ui.min.js
217
218
  - lib/populate_me/admin/__assets__/js/main.js
218
219
  - lib/populate_me/admin/__assets__/js/mustache.js
220
+ - lib/populate_me/admin/__assets__/js/quicksearch.js
219
221
  - lib/populate_me/admin/__assets__/js/sortable.js
220
222
  - lib/populate_me/admin/views/help.erb
221
223
  - lib/populate_me/admin/views/page.erb
@@ -256,7 +258,7 @@ homepage: https://github.com/mig-hub/populate-me
256
258
  licenses:
257
259
  - MIT
258
260
  metadata: {}
259
- post_install_message:
261
+ post_install_message:
260
262
  rdoc_options: []
261
263
  require_paths:
262
264
  - lib
@@ -271,8 +273,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
271
273
  - !ruby/object:Gem::Version
272
274
  version: '0'
273
275
  requirements: []
274
- rubygems_version: 3.0.3
275
- signing_key:
276
+ rubygems_version: 3.2.16
277
+ signing_key:
276
278
  specification_version: 4
277
279
  summary: PopulateMe is an admin system for web applications.
278
280
  test_files: