populate-me 0.11.0 → 0.14.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: 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: