hot-glue 0.5.8 → 0.5.9.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,15 +12,28 @@
12
12
  <% unless @no_list_heading %>
13
13
  <div class="<%= @layout_strategy.row_classes %> <%= @layout_strategy.row_heading_classes %>">
14
14
  <%= list_column_headings %>
15
+
15
16
  <% if @downnest_object.any? %>
16
- <%= @layout_strategy.downnest_column_style %>
17
- <% @downnest_object.each do |downnest,i| %>
18
- <div class=" scaffold-col-heading <%= @layout_strategy.downnest_portal_column_width(downnest) %> <%= @layout_strategy.downnest_column_style %>">
19
- <strong>
20
- <%= downnest.titleize %>
21
- </strong>
17
+ <% if !@stacked_downnesting %>
18
+ <%= @layout_strategy.downnest_column_style %>
19
+ <% @downnest_object.each do |downnest,i| %>
20
+ <div class=" scaffold-col-heading <%= @layout_strategy.downnest_portal_column_width(downnest) %> <%= @layout_strategy.downnest_column_style %>">
21
+ <strong>
22
+ <%= downnest.titleize %>
23
+ </strong>
24
+ </div>
25
+ <% end %>
26
+ <% else %>
27
+ <div class=" scaffold-col-heading <%= @layout_strategy.downnest_portal_stacked_column_width %> <%= @layout_strategy.downnest_column_style %>">
28
+ <%= @layout_strategy.downnest_column_style %>
29
+ <% @downnest_object.each do |downnest,i| %>
30
+ <strong>
31
+ <%= downnest.titleize %>
32
+ </strong>
33
+ <% end %>
22
34
  </div>
23
35
  <% end %>
36
+
24
37
  <% end %>
25
38
 
26
39
  <div class=' scaffold-col-heading scaffold-col-heading-buttons <%= @layout_strategy.column_classes_for_column_headings %>' <%= @layout_strategy.button_column_style %>>
@@ -1,16 +1,17 @@
1
1
  <%= all_line_fields %>
2
2
 
3
+
4
+
3
5
  <% if @downnest_children.any? %>
4
6
  <% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
5
-
7
+ <% if @stacked_downnesting %><div class="<%= @layout_strategy.downnest_portal_stacked_column_width %> scaffold-downnest" ><% end %>
6
8
  <% @downnest_object.each do |downnest, size| %>
7
-
8
9
  <% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest})") %>
9
10
  <% if downnest_object.nil?; raise "no relationship for downnested portal `#{downnest}` found on `#{singular_class}`; please check relationship for has_many :#{downnest}"; end; %>
10
11
  <% downnest_class = downnest_object.class_name %>
11
12
  <% downnest_object_name = eval("#{downnest_class}.table_name") %>
12
13
  <% downnest_style = @layout_strategy.downnest_style %>
13
- <div class="<%= @layout_strategy.downnest_portal_column_width(downnest) %> scaffold-downnest" <%= downnest_style %> >
14
+ <% if !@stacked_downnesting %><div class="<%= @layout_strategy.downnest_portal_column_width(downnest) %> scaffold-downnest" <%= downnest_style %> ><% end %>
14
15
  <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {
15
16
  <%= @singular %>: <%= @singular %>,
16
17
  <%= downnest_object_name %>: <%= @singular %>.<%= downnest %>
@@ -18,8 +19,9 @@
18
19
  .merge({nested_for: "<% if @nested_set.any? %>#{nested_for + "__" if defined?(nested_for)}<% end %><%= @singular %>-#{<%= @singular %>.id}"})
19
20
  <%= @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {} )"}.join("\n") %>
20
21
  \%>
21
- </div>
22
+ <% if !@stacked_downnesting %></div><% end %>
22
23
  <% end %>
24
+ <% if @stacked_downnesting %></div><% end %>
23
25
  <% end %>
24
26
 
25
27
  <%= @layout_strategy.button_style %>
@@ -0,0 +1,191 @@
1
+ import Dropzone from "dropzone";
2
+ import { Controller } from "@hotwired/stimulus"
3
+ import { DirectUpload } from "@rails/activestorage";
4
+
5
+ export default class extends Controller {
6
+ static targets = ["input"];
7
+
8
+ connect() {
9
+ this.dropZone = this.createDropZone(this);
10
+ this.hideFileInput();
11
+ this.bindEvents();
12
+ Dropzone.autoDiscover = false; // necessary quirk for Dropzone error in console
13
+ }
14
+
15
+ // helpers
16
+ getMetaValue(name) {
17
+ const element = this.findElement(document.head, `meta[name="${name}"]`);
18
+ if (element) {
19
+ return element.getAttribute("content");
20
+ }
21
+ }
22
+
23
+ findElement(root, selector) {
24
+ if (typeof root == "string") {
25
+ selector = root;
26
+ root = document;
27
+ }
28
+ return root.querySelector(selector);
29
+ }
30
+
31
+ toArray(value) {
32
+ if (Array.isArray(value)) {
33
+ return value;
34
+ } else if (Array.from) {
35
+ return Array.from(value);
36
+ } else {
37
+ return [].slice.call(value);
38
+ }
39
+ }
40
+
41
+
42
+ hideFileInput() {
43
+ this.inputTarget.disabled = true;
44
+ this.inputTarget.style.display = "none";
45
+ }
46
+
47
+ bindEvents() {
48
+ this.dropZone.on("addedfile", file => {
49
+ setTimeout(() => {
50
+ if (file.accepted) {
51
+ const duc = new DirectUploadProcessor(this, this.url(), file)
52
+ duc.start();
53
+ }
54
+ }, 500);
55
+ });
56
+
57
+ this.dropZone.on("removedfile", file => {
58
+ if(file.controller) {
59
+ file.controller.hiddenInput.parentNode.removeChild(file.controller.hiddenInput);
60
+ }
61
+ });
62
+
63
+ this.dropZone.on("canceled", file => {
64
+ file.controller && file.controller.xhr.abort();
65
+ });
66
+ }
67
+
68
+ url() {
69
+ return this.inputTarget.getAttribute("data-direct-upload-url");
70
+ }
71
+
72
+ createDropZone() {
73
+
74
+ return new Dropzone(this.element, {
75
+ url: this.url(),
76
+ headers: this.headers,
77
+ maxFiles: this.maxFiles,
78
+ maxFilesize: this.maxFileSize,
79
+ acceptedFiles: this.acceptedFiles,
80
+ addRemoveLinks: this.addRemoveLinks,
81
+ autoQueue: false
82
+ });
83
+ }
84
+
85
+ get headers() {
86
+ return { "X-CSRF-Token": this.getMetaValue("csrf-token") };
87
+ }
88
+
89
+ get maxFiles() {
90
+ return this.data.get("maxFiles") || 1;
91
+ }
92
+
93
+ get maxFileSize() {
94
+ return this.data.get("maxFileSize") || 256;
95
+ }
96
+
97
+ get acceptedFiles() {
98
+ return this.data.get("acceptedFiles");
99
+ }
100
+
101
+ get addRemoveLinks() {
102
+ return this.data.get("addRemoveLinks") || true;
103
+ }
104
+ }
105
+
106
+ class DirectUploadProcessor {
107
+ constructor(source, url, file) {
108
+ this.directUpload = createDirectUpload(file, url, this);
109
+ this.source = source;
110
+ this.file = file;
111
+ this.url = url;
112
+ }
113
+
114
+ insertAfter(el, referenceNode) {
115
+ return referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
116
+ }
117
+
118
+ start() {
119
+ this.file.controller = this;
120
+ this.hiddenInput = this.createHiddenInput();
121
+ this.directUpload.create((error, attributes) => {
122
+ if (error) {
123
+
124
+ this.hiddenInput.remove();
125
+ this.emitDropzoneError(error);
126
+ } else {
127
+ this.hiddenInput.value = attributes.signed_id;
128
+ this.emitDropzoneSuccess();
129
+ }
130
+ });
131
+ }
132
+
133
+ createHiddenInput() {
134
+ const input = document.createElement("input");
135
+ input.type = "hidden";
136
+ input.name = this.source.inputTarget.name;
137
+ this.insertAfter(input, this.source.inputTarget);
138
+ return input;
139
+ }
140
+
141
+ directUploadWillStoreFileWithXHR(xhr) {
142
+ this.bindProgressEvent(xhr);
143
+ this.emitDropzoneUploading();
144
+ }
145
+
146
+ bindProgressEvent(xhr) {
147
+ this.xhr = xhr;
148
+ this.xhr.upload.addEventListener("progress", event =>
149
+ this.uploadRequestDidProgress(event)
150
+ );
151
+ }
152
+
153
+ findElement(root, selector) {
154
+ if (typeof root == "string") {
155
+ selector = root;
156
+ root = document;
157
+ }
158
+ return root.querySelector(selector);
159
+ }
160
+
161
+ uploadRequestDidProgress(event) {
162
+ const element = this.source.element;
163
+ const progress = (event.loaded / event.total) * 100;
164
+ this.findElement(
165
+ this.file.previewTemplate,
166
+ ".dz-upload"
167
+ ).style.width = `${progress}%`;
168
+ }
169
+
170
+ emitDropzoneUploading() {
171
+ this.file.status = Dropzone.UPLOADING;
172
+ this.source.dropZone.emit("processing", this.file);
173
+ }
174
+
175
+ emitDropzoneError(error) {
176
+ this.file.status = Dropzone.ERROR;
177
+ this.source.dropZone.emit("error", this.file, error);
178
+ this.source.dropZone.emit("complete", this.file);
179
+ }
180
+
181
+ emitDropzoneSuccess() {
182
+ this.file.status = Dropzone.SUCCESS;
183
+ this.source.dropZone.emit("success", this.file);
184
+ this.source.dropZone.emit("complete", this.file);
185
+ }
186
+ }
187
+
188
+ function createDirectUpload(file, url, controller) {
189
+ return new DirectUpload(file, url, controller);
190
+ }
191
+
@@ -12,7 +12,7 @@ describe 'interaction for <%= controller_class_name %>' do
12
12
  item1_addOns << "#{display_class}: FFaker::Name.name"
13
13
  end
14
14
 
15
- item1_addOns << ", " + @columns.map { |col|
15
+ item1_addOns << ", " + (@columns - @attachments.keys.collect(&:to_sym)).map { |col|
16
16
  type = eval("#{singular_class}.columns_hash['#{col}']").type
17
17
  case type
18
18
  when :string
@@ -53,13 +53,15 @@ describe 'interaction for <%= controller_class_name %>' do
53
53
  <%= objest_nest_factory_setup %> <% unless @god || @existing_content.include?("login_as")%>
54
54
  before do
55
55
  login_as(<%= @auth %>)
56
- end <% end %>
57
-
56
+ end <% end %> <% if any_datetime_fields? %>
57
+ let(:current_timezone) {
58
+ <%= @auth_identifier %>.try(:timezone) || Time.now.strftime("%z").to_i/100
59
+ }<% end %>
58
60
  describe "index" do
59
61
  it "should show me the list" do
60
62
  visit <%= path_helper_plural %>
61
63
  <%=
62
- @columns.map { |col|
64
+ (@columns - @attachments.keys.collect(&:to_sym)).map { |col|
63
65
  type = eval("#{singular_class}.columns_hash['#{col}']").type
64
66
 
65
67
  case type
@@ -77,13 +79,13 @@ describe 'interaction for <%= controller_class_name %>' do
77
79
  if(eval("#{singular_class}.respond_to?(:#{col}_labels)"))
78
80
  " " + "expect(page).to have_content(#{singular_class}.#{col}_labels[#{singular}#{1}.#{col}])"
79
81
  else
80
- " " + "expect(page).to have_content(new_#{col})"
82
+ " " + "expect(page).to have_content(#{singular}1.#{col})"
81
83
  end
82
84
 
83
85
  when :boolean
84
86
  " " + ["expect(page).to have_content(#{singular}#{1}.#{col} ? 'YES' : 'NO')"].join("\n ")
85
87
  else
86
- " " + ["expect(page).to have_content(#{singular}#{1}.#{col})"].join("\n ")
88
+ " " + ["expect(page).to have_content(#{singular}#{1}.#{col})"].join("\n ")
87
89
  end
88
90
 
89
91
  }.join("\n")
@@ -101,7 +103,7 @@ describe 'interaction for <%= controller_class_name %>' do
101
103
  expect(page).to have_content("Successfully created")
102
104
  <%=" " +
103
105
 
104
- (@columns - @show_only).map { |col|
106
+ ((@columns - @attachments.keys.collect(&:to_sym)) - @show_only).map { |col|
105
107
  type = eval("#{singular_class}.columns_hash['#{col}']").type
106
108
 
107
109
  case type
@@ -144,7 +146,7 @@ describe 'interaction for <%= controller_class_name %>' do
144
146
  <%= test_capybara_block(:update) %>
145
147
  click_button "Save"
146
148
  within("turbo-frame#<%= @namespace %>__#{dom_id(<%= singular %>1)} ") do
147
- <%= (@columns - @show_only).map { |col|
149
+ <%= ((@columns - @attachments.keys.collect(&:to_sym)) - @show_only).map { |col|
148
150
  type = eval("#{singular_class}.columns_hash['#{col}']").type
149
151
 
150
152
  if type == :uuid || (type == :integer && col.to_s.ends_with?("_id"))
@@ -157,8 +159,14 @@ describe 'interaction for <%= controller_class_name %>' do
157
159
 
158
160
  elsif type == :enum && eval("#{singular_class}.respond_to?(:#{col}_labels)")
159
161
  " expect(page).to have_content(#{singular_class}.#{col}_labels[new_#{col}])"
162
+ elsif type == :string && eval("#{singular_class}.respond_to?(:devise_modules)") &&
163
+ #devise confirmable makes email updates go into unconfirmed_email
164
+ eval("#{singular_class}.devise_modules.include?(:confirmable)") && col.to_s == "email"
165
+ " expect(page).to have_content(#{ singular }1.#{col.to_s})"
166
+ elsif type == :datetime
167
+ " expect(page).to have_content(new_#{col.to_s}.in_time_zone(current_timezone).strftime('%m/%d/%Y @ %l:%M %p ') + timezonize(current_timezone))"
160
168
  else
161
- ' expect(page).to have_content(new_' + col.to_s + ')'
169
+ " expect(page).to have_content(new_#{col.to_s})"
162
170
  end
163
171
  }.compact.join("\n")
164
172
  %>
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.5.8'
3
+ CURRENT = '0.5.9.1'
4
4
  end
5
5
  end
@@ -18,7 +18,7 @@ rm -rf dummy/app/views/users/*
18
18
  rm -rf dummy/app/views/humans/*
19
19
  rm -rf dummy/app/views/pets/*
20
20
 
21
- /bin/rm -rf dummy/spec/system/
21
+ /bin/rm -rf dummy/spec/features/
22
22
 
23
23
 
24
24
  # !("application_controller.rb"|"welcome_controller.rb")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot-glue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.8
4
+ version: 0.5.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Fleetwood-Boldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-28 00:00:00.000000000 Z
11
+ date: 2023-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -75,6 +75,8 @@ files:
75
75
  - config/database.yml
76
76
  - config/hot_glue.yml
77
77
  - db/schema.rb
78
+ - lib/generators/hot_glue/direct_upload_install_generator.rb
79
+ - lib/generators/hot_glue/dropzone_install_generator.rb
78
80
  - lib/generators/hot_glue/install_generator.rb
79
81
  - lib/generators/hot_glue/layout/builder.rb
80
82
  - lib/generators/hot_glue/layout_strategy/base.rb
@@ -117,6 +119,7 @@ files:
117
119
  - lib/generators/hot_glue/templates/haml/index.haml
118
120
  - lib/generators/hot_glue/templates/haml/new.haml
119
121
  - lib/generators/hot_glue/templates/haml/update.turbo_stream.haml
122
+ - lib/generators/hot_glue/templates/javascript/dropzone_controller.js
120
123
  - lib/generators/hot_glue/templates/system_spec.rb.erb
121
124
  - lib/generators/hot_glue/templates/themes/hotglue_scaffold_dark_knight.scss
122
125
  - lib/generators/hot_glue/templates/themes/hotglue_scaffold_like_bootstrap.scss
@@ -131,9 +134,9 @@ homepage: https://heliosdev.shop/p/hot-glue?utm_source=rubygems.org&utm_campaign
131
134
  licenses:
132
135
  - Nonstandard
133
136
  metadata:
134
- source_code_uri: https://github.com/jasonfb/hot-glue
137
+ source_code_uri: https://github.com/hot-glue-for-rails/hot-glue
135
138
  homepage: https://heliosdev.shop/hot-glue
136
- funding: https://tekduds.com
139
+ funding: https://school.jasonfleetwoodboldt.com/8188
137
140
  post_install_message: |
138
141
  ---------------------------------------------
139
142
  Welcome to Hot Glue - A Scaffold Building Companion for Hotwire + Turbo-Rails