widget_list 2.0.0 → 2.0.2
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/README.md +93 -15
- data/app/views/widget_list/administration/_button_row.html.erb +2 -2
- data/app/views/widget_list/administration/_field_row.html.erb +2 -2
- data/app/views/widget_list/administration/_output.html.erb +89 -55
- data/checkin_gem.sh +1 -1
- data/docs/legacy-readme.md +13 -13
- data/docs/screenshots/admin1.jpg +0 -0
- data/docs/screenshots/admin2.jpg +0 -0
- data/docs/screenshots/admin3.jpg +0 -0
- data/docs/screenshots/admin4.jpg +0 -0
- data/docs/screenshots/admin5.png +0 -0
- data/docs/screenshots/admin6.png +0 -0
- data/docs/screenshots/filtered.png +0 -0
- data/docs/screenshots/main.png +0 -0
- data/docs/screenshots/ransack1.png +0 -0
- data/docs/screenshots/ransack2.png +0 -0
- data/docs/screenshots/ransack3.png +0 -0
- data/docs/screenshots/search.png +0 -0
- data/docs/screenshots/theme_blue_sky_basin.png +0 -0
- data/docs/widget-list-demo-thumbnail.png +0 -0
- data/lib/extensions/action_controller_base.rb +1 -0
- data/lib/widget_list/request_context.rb +1 -1
- data/lib/widget_list/version.rb +1 -1
- data/lib/widget_list.rb +52 -55
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 65e24eab11f0979fb9b5345f2abc750120245e1a3170c1c3cf4314650e01b42b
|
|
4
|
+
data.tar.gz: 49994c8e04a8fed60a7605cf896e78f79d6bdcabd5407a780ba8ceaeae9142fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4876ec92b2d1cf146f96d9b777575ff44ece4f3e707bed4098fef565025fc2a321246dbf200b084ef9ae847bd6822262ab39a68979213d9a2b3f8044f330399d
|
|
7
|
+
data.tar.gz: bbbeaf1232b1db0c48452af7dbd42b980e403ec3f3fb843aace3df2b9364af425256a945cc9dc3dea08e985853c2d4ec2d881e3d61b161b8236d2a6bc60d8cd9
|
data/README.md
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
# widget_list
|
|
2
2
|
|
|
3
|
-
`widget_list` renders sortable, searchable Rails data grids with Ajax paging and CSV export. Version 2.0.0 has been exercised with **Rails 8.1.4**, **Ruby 3.4.11**, **Sequel 5.109.0**, **Ransack 5.0.2**, and SQLite. Rails 8.1 requires Ruby 3.2 or newer. The Rails 3 era guide remains in [docs/legacy-readme.md](docs/legacy-readme.md) for reference.
|
|
3
|
+
`widget_list` renders sortable, searchable Rails data grids with Ajax paging and CSV export. Version 2.0.0 has been exercised with **Rails 8.1.4**, **Ruby 3.4.11**, **Sequel 5.109.0**, **Ransack 5.0.2**, and SQLite. The restored administration console is in the 2.0.1 source on `main`; publish 2.0.1 before installing it from RubyGems. Rails 8.1 requires Ruby 3.2 or newer. The Rails 3 era guide remains in [docs/legacy-readme.md](docs/legacy-readme.md) for reference.
|
|
4
4
|
|
|
5
5
|
The runnable [widget_list_example_rails8](https://github.com/davidrenne/widget_list_example_rails8/) contains both a Sequel SQL list and a Ransack/Active Record list. Its README and single commit diff show every caller change needed in a fresh Rails 8 app.
|
|
6
6
|
|
|
7
|
+
## Video demo
|
|
8
|
+
|
|
9
|
+
[](https://www.youtube.com/watch?v=A6mZa8Ge2Rk)
|
|
10
|
+
|
|
11
|
+
This video shows the original 1.x interface. For the Rails 8 integration, use the current example app below.
|
|
12
|
+
|
|
7
13
|
## Add it to a Rails 8 app
|
|
8
14
|
|
|
9
15
|
`widget_list` uses jQuery and Sprockets assets. In your Gemfile:
|
|
@@ -14,12 +20,6 @@ gem 'jquery-rails'
|
|
|
14
20
|
gem 'widget_list', '~> 2.0'
|
|
15
21
|
```
|
|
16
22
|
|
|
17
|
-
For local development before publishing version 2.0.0, replace the last line with:
|
|
18
|
-
|
|
19
|
-
```ruby
|
|
20
|
-
gem 'widget_list', path: '../widget_list'
|
|
21
|
-
```
|
|
22
|
-
|
|
23
23
|
Run `bundle install`. Add `app/assets/config/manifest.js`:
|
|
24
24
|
|
|
25
25
|
```javascript
|
|
@@ -44,10 +44,28 @@ Load the assets in the application layout's `<head>`:
|
|
|
44
44
|
```erb
|
|
45
45
|
<%= csrf_meta_tags %>
|
|
46
46
|
<%= stylesheet_link_tag 'application', 'widget_list', 'widgets' %>
|
|
47
|
-
<%= javascript_include_tag 'application'
|
|
47
|
+
<%= javascript_include_tag 'application' %>
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
The gem resolves its image URLs through Sprockets when compiling CSS. No manual image copy or static middleware is needed. An app using the default Rails 8 Propshaft pipeline should replace `propshaft` with `sprockets-rails` for this integration. Run `bin/rails assets:precompile` to check production assets.
|
|
50
|
+
Load this script in the layout's `<head>` without `defer`: the administration wizard's inline script needs jQuery as it is parsed. The gem resolves its image URLs through Sprockets when compiling CSS. No manual image copy or static middleware is needed. An app using the default Rails 8 Propshaft pipeline should replace `propshaft` with `sprockets-rails` for this integration. Run `bin/rails assets:precompile` to check production assets.
|
|
51
|
+
|
|
52
|
+
## Themes
|
|
53
|
+
|
|
54
|
+
`widget_list` lets a theme provide default colors, type, borders, and button styles through `WidgetListThemeHelper::ThemeDefaults`. Settings passed to an individual `WidgetList.go!` call override theme defaults. A theme can also ship a stylesheet for finer control.
|
|
55
|
+
|
|
56
|
+
| Theme | Appearance | Compatibility |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| [AI theme](https://github.com/davidrenne/widget_list_theme_ai) | Midnight surfaces, cyan and violet accents, modern grid controls | Built for widget_list 2.x and Rails 8 |
|
|
59
|
+
| [Cruddy](https://github.com/davidrenne/widget_list_theme_cruddy) | Warm, textured classic style | Legacy 1.x theme; requires migration for 2.x |
|
|
60
|
+
| [Blue Sky Basin](https://github.com/davidrenne/widget_list_theme_blue_sky_basin) | Blue mountain inspired palette | Legacy 1.x theme; requires migration for 2.x |
|
|
61
|
+
|
|
62
|
+
The AI theme is under development. To try it in your own Rails app, check out `widget_list_theme_ai` next to the app and add this line to its Gemfile:
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
gem 'widget_list_theme_ai', path: '../widget_list_theme_ai'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then run `bundle install`, add `//= link widget_list_theme_ai.css` to `app/assets/config/manifest.js`, and load `widget_list_theme_ai` after `widget_list` and `widgets` in the layout's `stylesheet_link_tag`. The theme uses a local system font stack and makes no external font request. See the [theme README on the preview branch](https://github.com/davidrenne/widget_list_theme_ai/tree/codex/ai-theme) for the complete setup and the example's `codex/ai-theme-example` branch for a working caller. That branch also uses the local core checkout for a pagination fix pending release.
|
|
51
69
|
|
|
52
70
|
## Choose a database source
|
|
53
71
|
|
|
@@ -118,10 +136,11 @@ A standard GET URL such as `/items?q[name_cont]=Apple` applies the filter. The g
|
|
|
118
136
|
|
|
119
137
|
## Try the example
|
|
120
138
|
|
|
121
|
-
|
|
139
|
+
The example installs the published 2.0.0 gem from RubyGems. Clone and run it anywhere:
|
|
122
140
|
|
|
123
141
|
```sh
|
|
124
|
-
|
|
142
|
+
git clone https://github.com/davidrenne/widget_list_example_rails8.git
|
|
143
|
+
cd widget_list_example_rails8
|
|
125
144
|
bundle install
|
|
126
145
|
bin/rails db:prepare
|
|
127
146
|
bin/rails db:seed
|
|
@@ -129,16 +148,75 @@ bin/rails test
|
|
|
129
148
|
bin/rails server
|
|
130
149
|
```
|
|
131
150
|
|
|
132
|
-
Open `http://127.0.0.1:3000/` for Sequel or `/ransack` for Active Record. Search SKU `1001`, change pages, export CSV, or open the filter arrow and set **Name contains Apple**.
|
|
151
|
+
Open `http://127.0.0.1:3000/` for Sequel or `/ransack` for Active Record. Search SKU `1001`, change pages, export CSV, or open the filter arrow and set **Name contains Apple**.
|
|
152
|
+
|
|
153
|
+
## Administration console
|
|
154
|
+
|
|
155
|
+
The original administration wizard is restored in the [Rails 8 migration example](https://github.com/davidrenne/widget_list_example). Open `/administration` there to choose an Active Record model and fields, configure sorting, search, row buttons and export, preview the list, then generate starter controller code. Hidden fields, field functions, grouping fields, and the drill-down value column use dropdowns populated from the selected model's table columns. The drill-down display column remains editable for custom expressions. The example routes the wizard only in development and test. It uses the sibling `widget_list` checkout, so the console fixes require the 2.0.1 source until that version is published.
|
|
156
|
+
|
|
157
|
+
To add the wizard to your own app, first complete the asset setup above. Then add a GET/POST route, a controller action, and a view:
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
# config/routes.rb
|
|
161
|
+
if Rails.env.development? || Rails.env.test?
|
|
162
|
+
match '/administration', to: 'widget_list_examples#administration',
|
|
163
|
+
via: [:get, :post], as: :administration
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# app/controllers/widget_list_examples_controller.rb
|
|
167
|
+
class WidgetListExamplesController < ApplicationController
|
|
168
|
+
def administration
|
|
169
|
+
@output = WidgetList.go!
|
|
170
|
+
render json: JSON.parse(@output) if params.key?(:ajax)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```erb
|
|
176
|
+
<%# app/views/widget_list_examples/administration.html.erb %>
|
|
177
|
+
<div style="margin: 50px"><%= raw @output %></div>
|
|
178
|
+
|
|
179
|
+
<%# Link from a page in development %>
|
|
180
|
+
<%= link_to 'Administration Console', administration_path if Rails.env.development? %>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
If `config/widget-list.yml` points `primary` at Sequel and `secondary` at Active Record, leave **Primary Connection?** unchecked when selecting a model. The wizard now defaults to that choice. Ransack requires the model's `ransackable_attributes` allowlist shown above. The generated action needs a GET/POST route and a view that renders `@output`, just like a hand-written list. Review the generated fields, links and controller code before using it. The wizard writes draft configuration to `config/widget-list-administration.json` and saved configurations to `config/widget-list-administration-all.json`; the example ignores both files in Git. Keep the route accessible only to trusted developers: the preview evaluates generated Ruby and the wizard writes files.
|
|
184
|
+
|
|
185
|
+
These are the original screenshots from the Rails 3 era. The Rails 8 wizard uses the same steps, while its generated code and preview have been updated for Rails 8 and Ransack 5.
|
|
186
|
+
|
|
187
|
+
| Start with a model | Configure search and export |
|
|
188
|
+
| --- | --- |
|
|
189
|
+
|  |  |
|
|
190
|
+
|
|
191
|
+
| Select fields | Configure row buttons |
|
|
192
|
+
| --- | --- |
|
|
193
|
+
|  |  |
|
|
194
|
+
|
|
195
|
+
| Preview the list | Generate controller code |
|
|
196
|
+
| --- | --- |
|
|
197
|
+
|  |  |
|
|
198
|
+
|
|
199
|
+
<details>
|
|
200
|
+
<summary>More original widget_list screenshots</summary>
|
|
201
|
+
|
|
202
|
+

|
|
203
|
+

|
|
204
|
+

|
|
205
|
+

|
|
206
|
+

|
|
207
|
+

|
|
208
|
+

|
|
209
|
+
|
|
210
|
+
</details>
|
|
133
211
|
|
|
134
212
|
## Release
|
|
135
213
|
|
|
136
|
-
The RubyGems page takes its short summary and longer description from `gem.summary` and `gem.description` in [widget_list.gemspec](widget_list.gemspec).
|
|
214
|
+
Version 2.0.0 is published; the administration console fixes are prepared as 2.0.1 on `main` and have not been published. The RubyGems page takes its short summary and longer description from `gem.summary` and `gem.description` in [widget_list.gemspec](widget_list.gemspec). To change them in a future release, bump `WidgetList::VERSION` in `lib/widget_list/version.rb` and publish a new version; published versions cannot be overwritten.
|
|
137
215
|
|
|
138
|
-
`./checkin_gem.sh` validates and builds the gem, and runs the sibling Rails 8 example tests when present. Review and commit your changes on `main`. Sign in to the command-line publisher with `gem signin` if needed, using an API key with the `push_rubygem` scope. A RubyGems website session does not sign in the `gem` command. Then run `./publish_gem.sh`; it checks that the tree is clean, builds the package, and pushes it to RubyGems.org. RubyGems may prompt for MFA in the terminal or open a browser for WebAuthn. No credential is stored in these scripts. Publishing is a separate, intentional step from committing.
|
|
216
|
+
`./checkin_gem.sh` validates and builds the gem, and runs the sibling local-source Rails 8 example tests when present. Review and commit your changes on `main`. Sign in to the command-line publisher with `gem signin` if needed, using an API key with the `push_rubygem` scope. A RubyGems website session does not sign in the `gem` command. Then run `./publish_gem.sh`; it checks that the tree is clean, builds the package, and pushes it to RubyGems.org. RubyGems may prompt for MFA in the terminal or open a browser for WebAuthn. No credential is stored in these scripts. Publishing is a separate, intentional step from committing.
|
|
139
217
|
|
|
140
218
|
See [RubyGems publishing](https://guides.rubygems.org/publishing/) and [MFA setup](https://guides.rubygems.org/setting-up-otp-mfa/) for account setup.
|
|
141
219
|
|
|
142
220
|
## Upgrade notes
|
|
143
221
|
|
|
144
|
-
The migration replaced Rails 3 callbacks and asset middleware, Ruby's removed `URI.decode`, unsafe SQL `eval`, and process-wide request globals. Ransack 5 requires explicit `ransackable_attributes` in each searchable model. The
|
|
222
|
+
The migration replaced Rails 3 callbacks and asset middleware, Ruby's removed `URI.decode`, unsafe SQL `eval`, and process-wide request globals. Ransack 5 requires explicit `ransackable_attributes` in each searchable model. The Rails 8 examples verify the list, Ajax search, pagination, advanced Ransack filtering, CSV export, and asset compilation. The migration example also exercises the administration wizard, its preview, and generated code. Non-SQLite adapters remain unverified.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<!--TEXT_DESC-->: <input type="text" class="<!--SUBJECT-->_<!--TEXT_KEY-->" style="width:170px" onblur="jQuery(this).attr('value',jQuery(this).val().trim());<!--ONBLUR1-->" name="<!--SUBJECT-->[<!--TEXT_KEY-->][]" id="<!--SUBJECT-->[<!--TEXT_KEY-->][]" value="<!--BUTTON_TEXT-->"/><%= raw WidgetList::Widgets::widget_button('?', {'onclick' => "alert('<!--TEXT_HELP-->')", 'innerClass' => "default <!--SUBJECT-->_<!--TEXT_KEY-->_button" }, true ) %>
|
|
4
4
|
</td>
|
|
5
5
|
<td>
|
|
6
|
-
<!--URL_DESC-->: 
|
|
6
|
+
<!--URL_DESC-->: <% if local_assigns[:middle_column_select] %><select class="<!--SUBJECT-->_<!--URL_KEY--> widget-list-column-select" style="width:170px" name="<!--SUBJECT-->[<!--URL_KEY-->][]" data-selected="<!--BUTTON_URL-->" onchange="<!--ONBLUR2-->"><option value="">Select a column</option></select><% else %><input type="text" class="<!--SUBJECT-->_<!--URL_KEY-->" style="width:170px" onblur="jQuery(this).attr('value',jQuery(this).val().trim());<!--ONBLUR2-->" name="<!--SUBJECT-->[<!--URL_KEY-->][]" id="<!--SUBJECT-->[<!--URL_KEY-->][]" value="<!--BUTTON_URL-->"/><% end %><%= raw WidgetList::Widgets::widget_button('?', {'onclick' => "alert('<!--2_HELP->')", 'innerClass' => "default <!--SUBJECT-->_<!--URL_KEY-->_button" }, true ) %>
|
|
7
7
|
</td>
|
|
8
8
|
<td>
|
|
9
9
|
<!--COLOR_DESC-->: <input type="text" class="<!--SUBJECT-->_<!--COLOR_KEY-->" style="width:170px" onblur="jQuery(this).attr('value',jQuery(this).val().trim());<!--ONBLUR3-->" name="<!--SUBJECT-->[<!--COLOR_KEY-->][]" id="<!--SUBJECT-->[<!--COLOR_KEY-->][]" value="<!--BUTTON_CLASS-->"/><%= raw WidgetList::Widgets::widget_button('?', {'onclick' => "alert('<!--COLOR_HELP-->')", 'innerClass' => "default <!--SUBJECT-->_<!--COLOR_KEY-->_button" }, true ) %>
|
|
@@ -11,4 +11,4 @@
|
|
|
11
11
|
<td>
|
|
12
12
|
<!--REMOVE_FIELD_BUTTON-->
|
|
13
13
|
</td>
|
|
14
|
-
</tr>
|
|
14
|
+
</tr>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<tr style="<!--TR_STYLE-->">
|
|
2
2
|
<td style="<!--TR1_STYLE-->">
|
|
3
|
-
<!--FIELD-->: 
|
|
3
|
+
<!--FIELD-->: <% if local_assigns[:key_select] %><select style="width:350px" class="<!--SUBJECT-->_keys widget-list-column-select" name="<!--SUBJECT-->[key][]" data-selected="<!--FIELD_VALUE-->" onchange="<!--ONBLUR1-->"><option value="">Select a column</option></select><% else %><input type="text" style="width:350px" class="<!--SUBJECT-->_keys" onblur="jQuery(this).attr('value',jQuery(this).val().trim());<!--ONBLUR1-->" name="<!--SUBJECT-->[key][]" id="<!--SUBJECT-->[key][]" value="<!--FIELD_VALUE-->"/><% end %>
|
|
4
4
|
</td>
|
|
5
5
|
<td>
|
|
6
6
|
<!--DESC-->: <input <!--DISABLED--> type="text" style="width:350px" class="<!--SUBJECT-->_descriptions" onblur="jQuery(this).attr('value',jQuery(this).val().trim());<!--ONBLUR2-->" name="<!--SUBJECT-->[description][]" id="<!--SUBJECT-->[description][]" value="<!--FIELD_DESC-->"/>
|
|
@@ -9,4 +9,4 @@
|
|
|
9
9
|
<!--REMOVE_FIELD_BUTTON-->
|
|
10
10
|
</td>
|
|
11
11
|
</tr>
|
|
12
|
-
<!--EXTRA-->
|
|
12
|
+
<!--EXTRA-->
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
var all = '.init,.start,.fields,.rows,.search,.footer,.misc_submit';
|
|
40
40
|
var all_btns = '#start,#fields,#rows,#search,#footer,#misc_submit';
|
|
41
41
|
jQuery(document).ready(function () {
|
|
42
|
+
PopulateColumnSelects();
|
|
43
|
+
jQuery(document).on('change', 'select.widget-list-column-select', function () {
|
|
44
|
+
jQuery(this).attr('data-selected', this.value);
|
|
45
|
+
});
|
|
42
46
|
if (jQuery('#view').val() != '') {
|
|
43
47
|
jQuery(all_btns).removeClass('disabled');
|
|
44
48
|
}
|
|
@@ -49,6 +53,9 @@
|
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
window.onbeforeunload = function (evt) {
|
|
56
|
+
if (isSubmitting) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
52
59
|
var message = 'Are you sure you want to abandon this widget_list implementation? Doing so will lose all your work?';
|
|
53
60
|
if (typeof evt == 'undefined') {
|
|
54
61
|
evt = window.event;
|
|
@@ -57,9 +64,7 @@
|
|
|
57
64
|
if (evt) {
|
|
58
65
|
evt.returnValue = message;
|
|
59
66
|
}
|
|
60
|
-
|
|
61
|
-
return message;
|
|
62
|
-
}
|
|
67
|
+
return message;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
70
|
});
|
|
@@ -82,33 +87,29 @@
|
|
|
82
87
|
var by_pass = false;
|
|
83
88
|
}
|
|
84
89
|
if (by_pass || VerifyOK(func_name)) {
|
|
85
|
-
jQuery('.search_dependent').hide(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
if (func_name == 'ShowFields') {
|
|
96
|
-
ShowHiddenOptions();
|
|
97
|
-
ShowFunctionOptions();
|
|
98
|
-
}
|
|
99
|
-
if (func_name == 'ShowSubmit') {
|
|
100
|
-
ShowCheckboxOptions();
|
|
101
|
-
}
|
|
102
|
-
if (func_name == 'ShowRows') {
|
|
103
|
-
ShowButtonOptions();
|
|
104
|
-
ShowDrillDownOptions();
|
|
105
|
-
}
|
|
106
|
-
if (func_name == 'ShowFooter') {
|
|
107
|
-
ShowFooterOptions();
|
|
108
|
-
}
|
|
109
|
-
});
|
|
90
|
+
jQuery('.search_dependent').hide();
|
|
91
|
+
jQuery(all).hide();
|
|
92
|
+
jQuery(which_class).show();
|
|
93
|
+
if (func_name == 'ShowSearch') {
|
|
94
|
+
ShowSearchOptions(function() {
|
|
95
|
+
ShowGroupingOptions();
|
|
96
|
+
ShowExportOptions();
|
|
110
97
|
});
|
|
111
|
-
}
|
|
98
|
+
}
|
|
99
|
+
if (func_name == 'ShowFields') {
|
|
100
|
+
ShowHiddenOptions();
|
|
101
|
+
ShowFunctionOptions();
|
|
102
|
+
}
|
|
103
|
+
if (func_name == 'ShowSubmit') {
|
|
104
|
+
ShowCheckboxOptions();
|
|
105
|
+
}
|
|
106
|
+
if (func_name == 'ShowRows') {
|
|
107
|
+
ShowButtonOptions();
|
|
108
|
+
ShowDrillDownOptions();
|
|
109
|
+
}
|
|
110
|
+
if (func_name == 'ShowFooter') {
|
|
111
|
+
ShowFooterOptions();
|
|
112
|
+
}
|
|
112
113
|
|
|
113
114
|
if (!by_pass) {
|
|
114
115
|
SaveChanges();
|
|
@@ -141,31 +142,60 @@
|
|
|
141
142
|
ClickTab('.misc_submit',arguments.callee.name);
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
function SetColumnValue(control, value) {
|
|
146
|
+
var field = jQuery(control);
|
|
147
|
+
if (field.is('select') && !field.find('option').filter(function () { return this.value == value; }).length) {
|
|
148
|
+
field.append(jQuery('<option>').val(value).text(value));
|
|
149
|
+
}
|
|
150
|
+
field.val(value);
|
|
151
|
+
field.attr(field.is('select') ? 'data-selected' : 'value', value);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function PopulateColumnSelects() {
|
|
155
|
+
var columns = jQuery('#checkboxField option').map(function () { return this.value; }).get().filter(Boolean);
|
|
156
|
+
if (!columns.length) return;
|
|
157
|
+
|
|
158
|
+
jQuery('select.widget-list-column-select').each(function () {
|
|
159
|
+
var field = jQuery(this);
|
|
160
|
+
var selected = field.val() || field.attr('data-selected') || '';
|
|
161
|
+
if (['column_name', 'col_name', 'field_name'].indexOf(selected) !== -1) selected = '';
|
|
162
|
+
|
|
163
|
+
field.empty().append(jQuery('<option>').val('').text(field.hasClass('group_by_keys') ? 'All items / select a column' : 'Select a column'));
|
|
164
|
+
columns.forEach(function (column) {
|
|
165
|
+
field.append(jQuery('<option>').val(column).text(column));
|
|
166
|
+
});
|
|
167
|
+
if (selected && columns.indexOf(selected) === -1) {
|
|
168
|
+
field.append(jQuery('<option>').val(selected).text(selected + ' (saved value)'));
|
|
169
|
+
}
|
|
170
|
+
SetColumnValue(field, selected);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
144
174
|
function ReplaceColumnsToLinked(obj) {
|
|
175
|
+
var isPassColumn = jQuery(obj).hasClass('drill_downs_data_to_pass_from_view');
|
|
176
|
+
var displayColumn = jQuery(obj).closest('tr').find('.drill_downs_column_to_show').val() || '';
|
|
177
|
+
if (isPassColumn && displayColumn.endsWith('_linked')) return;
|
|
145
178
|
found = false;
|
|
146
|
-
var className = obj.className;
|
|
147
179
|
jQuery(obj).css('background-color','white');
|
|
148
180
|
jQuery('.fields_keys, .fields_hidden_keys, .fields_function_keys').each(
|
|
149
181
|
function(key, value) {
|
|
150
182
|
if(jQuery(value).val() == jQuery(obj).val().trim() && jQuery(obj).val().search(/_linked/i) == -1) {
|
|
151
183
|
found = true;
|
|
152
184
|
var id_original = jQuery(obj).val().trim();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (className == 'drill_downs_data_to_pass_from_view') {
|
|
185
|
+
SetColumnValue(value, jQuery(obj).val().trim() + '_linked');
|
|
186
|
+
SetColumnValue(obj, isPassColumn ? id_original : id_original + '_linked');
|
|
187
|
+
if (isPassColumn) {
|
|
157
188
|
jQuery('.drill_downs_column_to_show[value="col_name"]').each(
|
|
158
189
|
function(key1, value1) {
|
|
159
|
-
jQuery(value1).val(
|
|
160
|
-
jQuery(value1).attr('value',
|
|
190
|
+
jQuery(value1).val(id_original + '_linked');
|
|
191
|
+
jQuery(value1).attr('value',id_original + '_linked');
|
|
161
192
|
return false;
|
|
162
193
|
}
|
|
163
194
|
)
|
|
164
195
|
} else {
|
|
165
|
-
jQuery('.drill_downs_data_to_pass_from_view
|
|
196
|
+
jQuery('.drill_downs_data_to_pass_from_view').filter(function () { return !this.value || this.value == 'col_name'; }).each(
|
|
166
197
|
function(key1, value1) {
|
|
167
|
-
|
|
168
|
-
jQuery(value1).attr('value',jQuery(value1).val().trim());
|
|
198
|
+
SetColumnValue(value1, id_original);
|
|
169
199
|
return false;
|
|
170
200
|
}
|
|
171
201
|
)
|
|
@@ -182,10 +212,9 @@
|
|
|
182
212
|
|
|
183
213
|
jQuery('#showHidden').attr('checked',true);
|
|
184
214
|
AddHiddenField();
|
|
185
|
-
jQuery('.fields_hidden_keys
|
|
215
|
+
jQuery('.fields_hidden_keys').filter(function () { return !this.value; }).each(
|
|
186
216
|
function(key1, value1) {
|
|
187
|
-
|
|
188
|
-
jQuery(value1).attr('value',id_original);
|
|
217
|
+
SetColumnValue(value1, id_original);
|
|
189
218
|
return false;
|
|
190
219
|
}
|
|
191
220
|
);
|
|
@@ -200,6 +229,7 @@
|
|
|
200
229
|
}
|
|
201
230
|
|
|
202
231
|
function InvalidField(obj) {
|
|
232
|
+
if (!jQuery(obj).val()) return;
|
|
203
233
|
found = false;
|
|
204
234
|
jQuery(obj).css('background-color','white');
|
|
205
235
|
jQuery('.fields_keys, .fields_hidden_keys, .fields_function_keys').each(
|
|
@@ -330,6 +360,7 @@
|
|
|
330
360
|
|
|
331
361
|
function AddGroupBy() {
|
|
332
362
|
jQuery('#grouping_table').html(jQuery('#grouping_table').html() + jQuery('#default_grouping_template').html());
|
|
363
|
+
PopulateColumnSelects();
|
|
333
364
|
}
|
|
334
365
|
|
|
335
366
|
function AddButton() {
|
|
@@ -339,6 +370,7 @@
|
|
|
339
370
|
|
|
340
371
|
function AddDrillDown() {
|
|
341
372
|
jQuery('#drill_down_table').html(jQuery('#drill_down_table').html() + jQuery('#default_drill_down_template').html());
|
|
373
|
+
PopulateColumnSelects();
|
|
342
374
|
}
|
|
343
375
|
|
|
344
376
|
function AddFooterButton() {
|
|
@@ -348,10 +380,12 @@
|
|
|
348
380
|
|
|
349
381
|
function AddHiddenField() {
|
|
350
382
|
jQuery('#hidden_field_table').html(jQuery('#hidden_field_table').html() + jQuery('#default_hidden_field_template').html());
|
|
383
|
+
PopulateColumnSelects();
|
|
351
384
|
}
|
|
352
385
|
|
|
353
386
|
function AddFieldFunction() {
|
|
354
387
|
jQuery('#field_function_table').html(jQuery('#field_function_table').html() + jQuery('#default_field_function_template').html());
|
|
388
|
+
PopulateColumnSelects();
|
|
355
389
|
}
|
|
356
390
|
|
|
357
391
|
function FakeCheck(obj) {
|
|
@@ -360,11 +394,11 @@
|
|
|
360
394
|
|
|
361
395
|
function RemoveField(obj) {
|
|
362
396
|
var isHiddenRemoval = false;
|
|
363
|
-
if (jQuery(obj).parent().parent().find('
|
|
397
|
+
if (jQuery(obj).parent().parent().find('.fields_hidden_keys').length > 0) {
|
|
364
398
|
isHiddenRemoval = true;
|
|
365
399
|
}
|
|
366
400
|
var isFunctionRemoval = false;
|
|
367
|
-
if (jQuery(obj).parent().parent().find('
|
|
401
|
+
if (jQuery(obj).parent().parent().find('.fields_function_keys').length > 0) {
|
|
368
402
|
isFunctionRemoval = true;
|
|
369
403
|
}
|
|
370
404
|
|
|
@@ -406,10 +440,9 @@
|
|
|
406
440
|
}
|
|
407
441
|
AddHiddenField();
|
|
408
442
|
jQuery('.hidden_fields_dependent').show();
|
|
409
|
-
jQuery('.fields_hidden_keys
|
|
443
|
+
jQuery('.fields_hidden_keys').filter(function () { return !this.value; }).each(
|
|
410
444
|
function(key1, value1) {
|
|
411
|
-
|
|
412
|
-
jQuery(value1).attr('value',field_name);
|
|
445
|
+
SetColumnValue(value1, field_name);
|
|
413
446
|
return false;
|
|
414
447
|
}
|
|
415
448
|
);
|
|
@@ -439,17 +472,16 @@
|
|
|
439
472
|
if (jQuery('#fieldFunctionOn').not(':checked')) {
|
|
440
473
|
jQuery('#fieldFunctionOn').attr('checked',true);
|
|
441
474
|
}
|
|
442
|
-
var objExists = '.fields_function_keys
|
|
443
|
-
if (
|
|
475
|
+
var objExists = jQuery('.fields_function_keys').filter(function () { return this.value == field_name; });
|
|
476
|
+
if (objExists.length > 0) {
|
|
444
477
|
alert('Field Function for ' + field_name + ' already exists, please modify');
|
|
445
478
|
jQuery(objExists).css('background-color','pink');
|
|
446
479
|
} else {
|
|
447
480
|
AddFieldFunction();
|
|
448
481
|
jQuery('.function_dependent').show();
|
|
449
|
-
jQuery('.fields_function_keys
|
|
482
|
+
jQuery('.fields_function_keys').filter(function () { return !this.value; }).each(
|
|
450
483
|
function(key1, value1) {
|
|
451
|
-
|
|
452
|
-
jQuery(value1).attr('value',field_name);
|
|
484
|
+
SetColumnValue(value1, field_name);
|
|
453
485
|
return false;
|
|
454
486
|
}
|
|
455
487
|
);
|
|
@@ -466,7 +498,7 @@
|
|
|
466
498
|
|
|
467
499
|
function ShowField(obj) {
|
|
468
500
|
|
|
469
|
-
var field_name = jQuery(obj).parent().parent().find('
|
|
501
|
+
var field_name = jQuery(obj).parent().parent().find('.fields_hidden_keys').val();
|
|
470
502
|
RemoveField(obj);
|
|
471
503
|
AddField();
|
|
472
504
|
jQuery('.fields_keys[value=""]').each(
|
|
@@ -504,6 +536,7 @@
|
|
|
504
536
|
jQuery('#checkboxField').html(response['checked_fields']);
|
|
505
537
|
jQuery('#footer_table').html(response['footer_buttons']);
|
|
506
538
|
jQuery('#grouping_table').html(response['group_by']);
|
|
539
|
+
PopulateColumnSelects();
|
|
507
540
|
SaveChanges();
|
|
508
541
|
if (jQuery(obj).val() != '') {
|
|
509
542
|
jQuery(all_btns).removeClass('disabled');
|
|
@@ -521,7 +554,7 @@
|
|
|
521
554
|
if (jQuery(obj).val() != '' && jQuery('#showExport').is(':checked')) {
|
|
522
555
|
jQuery('#exportButtonTitle').val('Export All ' + jQuery(obj).val() + 's');
|
|
523
556
|
}
|
|
524
|
-
}, "json").
|
|
557
|
+
}, "json").fail(function(response) {
|
|
525
558
|
alert('An error occurred instantiating this model. Check the response for errors.');
|
|
526
559
|
});
|
|
527
560
|
}
|
|
@@ -568,6 +601,7 @@
|
|
|
568
601
|
|
|
569
602
|
</script>
|
|
570
603
|
<form action="<!--POST_URL-->" method="post" id="widget_list_administration">
|
|
604
|
+
<input type="hidden" name="authenticity_token" value="<!--AUTH_TOKEN-->"/>
|
|
571
605
|
<h1 style="font-size:24;"><!--TITLE--></h1><div class="horizontal_rule"></div>
|
|
572
606
|
<h3>Get started quickly by selecting the features you need for this list</h3>
|
|
573
607
|
<table>
|
|
@@ -1098,4 +1132,4 @@
|
|
|
1098
1132
|
</tr>
|
|
1099
1133
|
|
|
1100
1134
|
</table>
|
|
1101
|
-
</form>
|
|
1135
|
+
</form>
|
data/checkin_gem.sh
CHANGED
|
@@ -5,7 +5,7 @@ cd "$(dirname "$0")"
|
|
|
5
5
|
version=$(ruby -Ilib -rwidget_list/version -e 'print WidgetList::VERSION')
|
|
6
6
|
gem build widget_list.gemspec --output "widget_list-${version}.gem"
|
|
7
7
|
|
|
8
|
-
example_dir="../
|
|
8
|
+
example_dir="../widget_list_example"
|
|
9
9
|
if [[ -f "${example_dir}/bin/rails" ]]; then
|
|
10
10
|
(cd "$example_dir" && bundle install && bin/rails test)
|
|
11
11
|
fi
|
data/docs/legacy-readme.md
CHANGED
|
@@ -65,31 +65,31 @@ In rails you have will_paginate and other ones like it using the ActiveRecord ap
|
|
|
65
65
|
|
|
66
66
|
### Main Example Loaded:
|
|
67
67
|
|
|
68
|
-

|
|
69
69
|
|
|
70
70
|
###Filter Drop Downs:
|
|
71
71
|
|
|
72
|
-

|
|
73
73
|
|
|
74
74
|
###Searching a row (with wild card search):
|
|
75
75
|
|
|
76
|
-

|
|
77
77
|
|
|
78
78
|
###Searching "name=asdf_18" (With ActiveRecord and Ransack hook):
|
|
79
79
|
|
|
80
|
-

|
|
81
81
|
|
|
82
82
|
###Searching "name=asdf_18" and "sku<9000"(With ActiveRecord and Ransack hook):
|
|
83
83
|
|
|
84
|
-

|
|
85
85
|
|
|
86
86
|
###Searching "name=asdf_18" and "sku < 9000" and "price > 67" (With ActiveRecord and Ransack hook):
|
|
87
87
|
|
|
88
|
-

|
|
89
89
|
|
|
90
90
|
###Theme plugins/gem support ([The Blue Sky Basin Theme][2]):
|
|
91
91
|
|
|
92
|
-

|
|
93
93
|
|
|
94
94
|
****
|
|
95
95
|
|
|
@@ -114,21 +114,21 @@ And then add this to a clean controller. If you have code below, please return
|
|
|
114
114
|
|
|
115
115
|
Next you will see this interface which will build some starter code for you:
|
|
116
116
|
|
|
117
|
-

|
|
118
118
|
|
|
119
|
-

|
|
120
120
|
|
|
121
|
-

|
|
122
122
|
|
|
123
|
-

|
|
124
124
|
|
|
125
125
|
###As you can see below, there is a preview iframe of what you are configuring:
|
|
126
126
|
|
|
127
|
-

|
|
128
128
|
|
|
129
129
|
###And finally, the code is output to get you started
|
|
130
130
|
|
|
131
|
-

|
|
132
132
|
|
|
133
133
|
****
|
|
134
134
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/widget_list/version.rb
CHANGED
data/lib/widget_list.rb
CHANGED
|
@@ -43,10 +43,12 @@ module WidgetList
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
#Loop models
|
|
46
|
-
models = Dir[
|
|
46
|
+
models = Dir[Rails.root.join('app', 'models', '**', '*.rb').to_s].reject do |path|
|
|
47
|
+
File.basename(path) == 'application_record.rb'
|
|
48
|
+
end
|
|
47
49
|
if !models.empty?
|
|
48
50
|
model_options = '<option value="">Select a Model</option>' + models.collect { |model|
|
|
49
|
-
model_name =
|
|
51
|
+
model_name = File.basename(model, '.rb').camelize
|
|
50
52
|
"<option value='#{model_name}' #{((@isEditing && page_config['view'] == model_name) ? 'selected' : '')}>#{model_name}</option>"
|
|
51
53
|
}.sort.uniq.join('')
|
|
52
54
|
else
|
|
@@ -119,7 +121,10 @@ module WidgetList
|
|
|
119
121
|
@fill['<!--VIEW_OPTIONS-->'] = model_options
|
|
120
122
|
@fill['<!--TITLE_VALUE-->'] = (!@isEditing) ? '' : page_config['title']
|
|
121
123
|
@fill['<!--DESC_VALUE-->'] = (!@isEditing) ? '' : page_config['listDescription']
|
|
122
|
-
|
|
124
|
+
WidgetList::List.load_widget_list_yml
|
|
125
|
+
primary_is_active_record = !$widget_list_conf[:primary].to_s.include?(':/')
|
|
126
|
+
@fill['<!--PRIMARY_CHECKED-->'] = (!@isEditing) ? (primary_is_active_record ? 'checked' : '') : (page_config['primaryDatabase'] == "1") ? 'checked' : ''
|
|
127
|
+
@fill['<!--AUTH_TOKEN-->'] = ERB::Util.html_escape(WidgetList::RequestContext.csrf_token.to_s)
|
|
123
128
|
|
|
124
129
|
#
|
|
125
130
|
# FIELD LEVEL
|
|
@@ -188,7 +193,8 @@ module WidgetList
|
|
|
188
193
|
@fieldFill['<!--DESC-->'] = 'Desc'
|
|
189
194
|
@fieldFill['<!--DISABLED-->'] = 'disabled'
|
|
190
195
|
@fieldFill['<!--TR_STYLE-->'] = ''
|
|
191
|
-
@
|
|
196
|
+
@fieldFill['<!--ONBLUR1-->'] = ''
|
|
197
|
+
@fill['<!--HIDDEN_FIELD_TEMPLATE-->'] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row', :locals => { :key_select => true }) )
|
|
192
198
|
@fill['<!--ADD_HIDDEN_FIELD_BUTTON-->'] = WidgetList::Widgets::widget_button('Add Hidden Field', {'onclick' => "AddHiddenField();", 'innerClass' => "success" } )
|
|
193
199
|
@fill['<!--ALL_HIDDEN_FIELDS-->'] = (!@isEditing) ? '' : page_json['fields_hidden']
|
|
194
200
|
|
|
@@ -203,7 +209,8 @@ module WidgetList
|
|
|
203
209
|
@fieldFill['<!--DESC-->'] = 'Database Function'
|
|
204
210
|
@fieldFill['<!--DISABLED-->'] = ''
|
|
205
211
|
@fieldFill['<!--TR_STYLE-->'] = ''
|
|
206
|
-
@
|
|
212
|
+
@fieldFill['<!--ONBLUR1-->'] = ''
|
|
213
|
+
@fill['<!--FIELD_FUNCTION_TEMPLATE-->'] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row', :locals => { :key_select => true }) )
|
|
207
214
|
@fill['<!--ADD_FIELD_FUNCTION_BUTTON-->'] = WidgetList::Widgets::widget_button('Add Function', {'onclick' => "AddFieldFunction();", 'innerClass' => "success" } )
|
|
208
215
|
@fill['<!--ALL_FIELD_FUNCTIONS-->'] = (!@isEditing) ? '' : page_json['fields_function']
|
|
209
216
|
|
|
@@ -261,7 +268,7 @@ module WidgetList
|
|
|
261
268
|
@fieldFill['<!--COLOR_HELP-->'] = ':column_to_show should either be the column or possibly a formatted column like CONCAT or COUNT'
|
|
262
269
|
@fieldFill['<!--SUBJECT-->'] = 'drill_downs'
|
|
263
270
|
|
|
264
|
-
@fill['<!--THE_DRILL_DOWN_TEMPLATE-->'] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') )
|
|
271
|
+
@fill['<!--THE_DRILL_DOWN_TEMPLATE-->'] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row', :locals => { :middle_column_select => true }) )
|
|
265
272
|
@fill['<!--ADD_DRILL_DOWN_BUTTON-->'] = WidgetList::Widgets::widget_button('Add New Drill Down', {'onclick' => "AddDrillDown();", 'innerClass' => "success" } )
|
|
266
273
|
@fill['<!--ALL_DRILL_DOWNS-->'] = page_json['drill_downs']
|
|
267
274
|
|
|
@@ -278,7 +285,7 @@ module WidgetList
|
|
|
278
285
|
|
|
279
286
|
@fieldFill = {}
|
|
280
287
|
@fieldFill['<!--REMOVE_FIELD_BUTTON-->'] = remove_field_button()
|
|
281
|
-
@fieldFill['<!--FIELD_VALUE-->'] = '
|
|
288
|
+
@fieldFill['<!--FIELD_VALUE-->'] = ''
|
|
282
289
|
@fieldFill['<!--FIELD_DESC-->'] = 'User Desc'
|
|
283
290
|
@fieldFill['<!--SUBJECT-->'] = 'group_by'
|
|
284
291
|
@fieldFill['<!--FIELD-->'] = 'Field'
|
|
@@ -286,7 +293,7 @@ module WidgetList
|
|
|
286
293
|
@fieldFill['<!--DISABLED-->'] = ''
|
|
287
294
|
@fieldFill['<!--ONBLUR1-->'] = 'InvalidField(this)'
|
|
288
295
|
@fieldFill['<!--TR_STYLE-->'] = ''
|
|
289
|
-
@fill['<!--DEFAULT_GROUPING-->'] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') )
|
|
296
|
+
@fill['<!--DEFAULT_GROUPING-->'] = WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row', :locals => { :key_select => true }) )
|
|
290
297
|
@fill['<!--ADD_GROUP_BY_BUTTON-->'] = WidgetList::Widgets::widget_button('Add New Group By', {'onclick' => "AddGroupBy();", 'innerClass' => "success" } )
|
|
291
298
|
@fill['<!--GROUPING_ITEMS-->'] = (!@isEditing) ? '' : page_json['group_by']
|
|
292
299
|
|
|
@@ -415,6 +422,7 @@ module WidgetList
|
|
|
415
422
|
list_parms['searchFieldsOut']#{add_pointer(field[1]['column_to_show'],9)} true"
|
|
416
423
|
|
|
417
424
|
column_to_show = "'#{field[1]['column_to_show'].gsub(/_linked/,'')}'"
|
|
425
|
+
data_to_pass = "'#{field[1]['data_to_pass_from_view'].gsub(/_linked/,'')}'"
|
|
418
426
|
if using_grouping
|
|
419
427
|
if database_type == 'oracle'
|
|
420
428
|
column_to_show = "groupByFilter == 'none' ? '#{escape_code field[1]['column_to_show'].gsub(/_linked/,'')}' : 'MAX(#{escape_code field[1]['column_to_show'].gsub(/_linked/,'')})'"
|
|
@@ -425,22 +433,17 @@ module WidgetList
|
|
|
425
433
|
list_parms['fieldFunction']#{add_pointer(field[1]['column_to_show'],7)} WidgetList::List::build_drill_down(
|
|
426
434
|
:list_id => list_parms['name'],
|
|
427
435
|
:drill_down_name => '#{escape_code field[0]}',
|
|
428
|
-
:data_to_pass_from_view => #{
|
|
436
|
+
:data_to_pass_from_view => #{data_to_pass},
|
|
429
437
|
:column_to_show => #{column_to_show},
|
|
430
438
|
:column_alias => '#{escape_code field[1]['column_to_show']}',
|
|
431
439
|
:primary_database => #{page_config['primaryDatabase'] == '1' ? 'true' : 'false'}
|
|
432
440
|
)"
|
|
433
|
-
if $is_mongo
|
|
434
|
-
code = "filterValue"
|
|
435
|
-
else
|
|
436
|
-
code = "#{page_config['view']}.sanitize(filterValue)"
|
|
437
|
-
end
|
|
438
441
|
case_statements += <<-EOD
|
|
439
442
|
|
|
440
443
|
when '#{field[0]}'
|
|
441
|
-
list_parms['filter'] << " #{field[1]['
|
|
442
|
-
list_parms['bindVars'] <<
|
|
443
|
-
list_parms['listDescription'] = drillDownBackLink + ' Filtered by #{escape_code field[1]['
|
|
444
|
+
list_parms['filter'] << " #{field[1]['data_to_pass_from_view'].gsub(/_linked/,'')} = ? "
|
|
445
|
+
list_parms['bindVars'] << filterValue
|
|
446
|
+
list_parms['listDescription'] = drillDownBackLink + ' Filtered by #{escape_code field[1]['data_to_pass_from_view'].gsub(/_linked/,'').camelize} (' + filterValue + ')'
|
|
444
447
|
EOD
|
|
445
448
|
}
|
|
446
449
|
|
|
@@ -595,7 +598,7 @@ module WidgetList
|
|
|
595
598
|
|
|
596
599
|
if page_config['useRansack'] == '1' && page_config['showSearch'] == '1' && $is_mongo == false
|
|
597
600
|
view_code = "
|
|
598
|
-
list_parms#{add_pointer('ransackSearch',-10)} #{page_config['view']}.
|
|
601
|
+
list_parms#{add_pointer('ransackSearch',-10)} #{page_config['view']}.ransack(#{(WidgetList::RequestContext.request.key?('iframe')) ? 'WidgetList::RequestContext.request' : 'params'}[:q])
|
|
599
602
|
list_parms#{add_pointer('view',-10)} list_parms['ransackSearch'].result
|
|
600
603
|
"
|
|
601
604
|
if page_config['ransackAdvancedForm'] == '1'
|
|
@@ -622,7 +625,7 @@ module WidgetList
|
|
|
622
625
|
|
|
623
626
|
else
|
|
624
627
|
view_code = "
|
|
625
|
-
list_parms#{add_pointer('view',-10)} #{page_config['view']}
|
|
628
|
+
list_parms#{add_pointer('view',-10)} #{page_config['view']}.all
|
|
626
629
|
"
|
|
627
630
|
end
|
|
628
631
|
|
|
@@ -807,8 +810,6 @@ module WidgetList
|
|
|
807
810
|
end
|
|
808
811
|
|
|
809
812
|
<<-EOD
|
|
810
|
-
begin
|
|
811
|
-
|
|
812
813
|
#{variable_code}
|
|
813
814
|
list_parms = WidgetList::List::init_config()
|
|
814
815
|
list_parms['name'] = '#{escape_code page_config['name']}'
|
|
@@ -849,35 +850,14 @@ module WidgetList
|
|
|
849
850
|
when 'html'
|
|
850
851
|
@output = output
|
|
851
852
|
when 'json'
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
rescue Exception => e
|
|
859
|
-
|
|
860
|
-
#
|
|
861
|
-
# Rescue Errors
|
|
862
|
-
#
|
|
863
|
-
Rails.logger.info e.to_s + "\\n\\n" + $!.backtrace.join("\\n\\n")
|
|
864
|
-
|
|
865
|
-
if Rails.env == 'development'
|
|
866
|
-
list_parms['errors'] << '<br/><br/><strong style="color:maroon;">(Ruby Exception - Still attempted to render list with given config ' + list_parms.inspect + ') Exception ==> ' + e.to_s + "<br/><br/>Backtrace:<br/><br/>" + $!.backtrace.join("<br/><br/>") + "</strong>"
|
|
867
|
-
end
|
|
868
|
-
|
|
869
|
-
output_type, output = WidgetList::List.build_list(list_parms)
|
|
870
|
-
|
|
871
|
-
case output_type
|
|
872
|
-
when 'html'
|
|
873
|
-
@output = output
|
|
874
|
-
when 'json'
|
|
875
|
-
return render :inline => output
|
|
853
|
+
if WidgetList::RequestContext.request.key?('iframe')
|
|
854
|
+
@output = output
|
|
855
|
+
else
|
|
856
|
+
render json: JSON.parse(output)
|
|
857
|
+
end
|
|
876
858
|
when 'export'
|
|
877
|
-
send_data
|
|
878
|
-
return
|
|
859
|
+
send_data output, filename: list_parms['name'] + '.csv', type: 'text/csv'
|
|
879
860
|
end
|
|
880
|
-
end
|
|
881
861
|
EOD
|
|
882
862
|
end
|
|
883
863
|
|
|
@@ -1062,7 +1042,6 @@ module WidgetList
|
|
|
1062
1042
|
buttons['Edit']['class'] = 'info'
|
|
1063
1043
|
if WidgetList::RequestContext.request.key?('ajax')
|
|
1064
1044
|
group_by[''] = 'All ' + model_name + 's'
|
|
1065
|
-
group_by['field_name'] = 'This will group by field_name and show Count'
|
|
1066
1045
|
buttons['Delete']['url'] = '/' + controller + '/delete/' + fields.keys.first + '/'
|
|
1067
1046
|
buttons['Edit']['url'] = '/' + controller + '/edit/' + fields.keys.first + '/'
|
|
1068
1047
|
end
|
|
@@ -1171,7 +1150,8 @@ module WidgetList
|
|
|
1171
1150
|
@fieldFill['<!--FIELD-->'] = 'Field'
|
|
1172
1151
|
@fieldFill['<!--DISABLED-->'] = 'disabled'
|
|
1173
1152
|
@fieldFill['<!--TR_STYLE-->'] = ''
|
|
1174
|
-
@
|
|
1153
|
+
@fieldFill['<!--ONBLUR1-->'] = ''
|
|
1154
|
+
@response['fields_hidden'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row', :locals => { :key_select => true }) )
|
|
1175
1155
|
}
|
|
1176
1156
|
|
|
1177
1157
|
group_by.each { |field,description|
|
|
@@ -1186,7 +1166,7 @@ module WidgetList
|
|
|
1186
1166
|
@fieldFill['<!--DISABLED-->'] = ''
|
|
1187
1167
|
@fieldFill['<!--ONBLUR1-->'] = 'InvalidField(this)'
|
|
1188
1168
|
@fieldFill['<!--TR_STYLE-->'] = ''
|
|
1189
|
-
@response['group_by'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row') )
|
|
1169
|
+
@response['group_by'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row', :locals => { :key_select => true }) )
|
|
1190
1170
|
}
|
|
1191
1171
|
|
|
1192
1172
|
fields_function.each { |field,description|
|
|
@@ -1199,7 +1179,8 @@ module WidgetList
|
|
|
1199
1179
|
@fieldFill['<!--FIELD-->'] = 'Field'
|
|
1200
1180
|
@fieldFill['<!--DISABLED-->'] = ''
|
|
1201
1181
|
@fieldFill['<!--TR_STYLE-->'] = ''
|
|
1202
|
-
@
|
|
1182
|
+
@fieldFill['<!--ONBLUR1-->'] = ''
|
|
1183
|
+
@response['fields_function'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/field_row', :locals => { :key_select => true }) )
|
|
1203
1184
|
}
|
|
1204
1185
|
|
|
1205
1186
|
buttons.each { |field|
|
|
@@ -1249,7 +1230,7 @@ module WidgetList
|
|
|
1249
1230
|
@fieldFill['<!--COLOR_HELP-->'] = ':column_to_show should either be the column or possibly a formatted column like CONCAT or COUNT'
|
|
1250
1231
|
@fieldFill['<!--SUBJECT-->'] = 'drill_downs'
|
|
1251
1232
|
|
|
1252
|
-
@response['drill_downs'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row') )
|
|
1233
|
+
@response['drill_downs'] += WidgetList::Utils::fill(@fieldFill , ac.render_to_string(:partial => 'widget_list/administration/button_row', :locals => { :middle_column_select => true }) )
|
|
1253
1234
|
}
|
|
1254
1235
|
|
|
1255
1236
|
footer_buttons.each { |field|
|
|
@@ -1838,7 +1819,7 @@ module WidgetList
|
|
|
1838
1819
|
@items['LIST_SEQUENCE'] = 1
|
|
1839
1820
|
end
|
|
1840
1821
|
|
|
1841
|
-
if @items['LIST_SEQUENCE'].
|
|
1822
|
+
if @items['LIST_SEQUENCE'].is_a?(Integer) && @items['LIST_SEQUENCE'] > 0
|
|
1842
1823
|
@sequence = @items['LIST_SEQUENCE'].to_i
|
|
1843
1824
|
end
|
|
1844
1825
|
|
|
@@ -2426,6 +2407,16 @@ module WidgetList
|
|
|
2426
2407
|
listJumpUrl['LIST_NAME'] = @items['name']
|
|
2427
2408
|
listJumpUrl['SQL_HASH'] = @sqlHash
|
|
2428
2409
|
|
|
2410
|
+
# Initial links inherit request parameters in build_url. Ajax links
|
|
2411
|
+
# need the preview context copied because build_url skips that step.
|
|
2412
|
+
if WidgetList::RequestContext.request.key?('BUTTON_VALUE')
|
|
2413
|
+
%w[iframe desiredController desiredAction].each do |key|
|
|
2414
|
+
if WidgetList::RequestContext.request.key?(key)
|
|
2415
|
+
listJumpUrl[key] = WidgetList::RequestContext.request[key]
|
|
2416
|
+
end
|
|
2417
|
+
end
|
|
2418
|
+
end
|
|
2419
|
+
|
|
2429
2420
|
if WidgetList::RequestContext.request.key?('switch_grouping')
|
|
2430
2421
|
listJumpUrl['switch_grouping'] = WidgetList::RequestContext.request['switch_grouping']
|
|
2431
2422
|
end
|
|
@@ -3421,7 +3412,13 @@ module WidgetList
|
|
|
3421
3412
|
if WidgetList::List.get_db_type(items[:primary_database]) == 'oracle'
|
|
3422
3413
|
link = %[q'[<a style='cursor:pointer;color:#{items[:link_color]};' class='#{items[:column_alias]}_drill#{items[:column_class]}' onclick='#{items[:js_function_name]}("#{items[:drill_down_name]}", ListDrillDownGetRowValue(this) ,"#{items[:list_id]}"#{items[:extra_js_func_params]});#{items[:extra_function]}'>]' #{WidgetList::List::concat_string(items[:primary_database])}#{items[:column_to_show]}#{WidgetList::List::concat_string(items[:primary_database])}q'[</a><script class='val-db' type='text'>]' #{WidgetList::List::concat_string(items[:primary_database])} #{items[:data_to_pass_from_view]} #{WidgetList::List::concat_string(items[:primary_database])} q'[</script>]' #{WidgetList::List::concat_outer(items[:primary_database])} #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}]
|
|
3423
3414
|
else
|
|
3424
|
-
if WidgetList::List.get_db_type(items[:primary_database]) == '
|
|
3415
|
+
if WidgetList::List.get_db_type(items[:primary_database]) == 'sqlite'
|
|
3416
|
+
sql_literal = ->(value) { "'#{value.gsub("'", "''")}'" }
|
|
3417
|
+
prefix = %(<a style="cursor:pointer;color:#{items[:link_color]};" class="#{items[:column_alias]}_drill#{items[:column_class]}" onclick="#{items[:js_function_name]}('#{items[:drill_down_name]}', ListDrillDownGetRowValue(this) ,'#{items[:list_id]}'#{items[:extra_js_func_params]});#{items[:extra_function]}">)
|
|
3418
|
+
middle = '</a><script class="val-db" type="text">'
|
|
3419
|
+
suffix = '</script>'
|
|
3420
|
+
link = "#{sql_literal.call(prefix)} || #{items[:column_to_show]} || #{sql_literal.call(middle)} || #{items[:data_to_pass_from_view]} || #{sql_literal.call(suffix)}#{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]}" : ''}"
|
|
3421
|
+
elsif WidgetList::List.get_db_type(items[:primary_database]) == 'postgres'
|
|
3425
3422
|
link = %['<a style="cursor:pointer;color:#{items[:link_color]};" class="#{items[:column_alias]}_drill#{items[:column_class]}" onclick="#{items[:js_function_name]}(''#{items[:drill_down_name]}'', ListDrillDownGetRowValue(this) ,''#{items[:list_id]}''#{items[:extra_js_func_params]});#{items[:extra_function]}">"' #{WidgetList::List::concat_string(items[:primary_database])}#{items[:column_to_show]}#{WidgetList::List::concat_string(items[:primary_database])}'</a><script class="val-db" type="text">' #{WidgetList::List::concat_string(items[:primary_database])} #{items[:data_to_pass_from_view]} #{WidgetList::List::concat_string(items[:primary_database])}'</script>' #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}]
|
|
3426
3423
|
else
|
|
3427
3424
|
link = %[#{WidgetList::List::concat_inner(items[:primary_database])}"<a style='cursor:pointer;color:#{items[:link_color]};' class='#{items[:column_alias]}_drill#{items[:column_class]}' onclick='#{items[:js_function_name]}(#{WidgetList::List::double_quote(items[:primary_database])}#{items[:drill_down_name]}#{WidgetList::List::double_quote(items[:primary_database])}, ListDrillDownGetRowValue(this) ,#{WidgetList::List::double_quote(items[:primary_database])}#{items[:list_id]}#{WidgetList::List::double_quote(items[:primary_database])}#{items[:extra_js_func_params]});#{items[:extra_function]}'>"#{WidgetList::List::concat_string(items[:primary_database])}#{items[:column_to_show]}#{WidgetList::List::concat_string(items[:primary_database])}"</a><script class='val-db' type='text'>"#{WidgetList::List::concat_string(items[:primary_database])} #{items[:data_to_pass_from_view]} #{WidgetList::List::concat_string(items[:primary_database])}"</script>"#{WidgetList::List::concat_outer(items[:primary_database])} #{WidgetList::List::is_sequel(items[:primary_database]) ? " as #{items[:column_alias]} " : ""}]
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: widget_list
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Renne
|
|
@@ -93,6 +93,20 @@ files:
|
|
|
93
93
|
- app/views/widget_list/list_partials/_sort_column.html.erb
|
|
94
94
|
- checkin_gem.sh
|
|
95
95
|
- docs/legacy-readme.md
|
|
96
|
+
- docs/screenshots/admin1.jpg
|
|
97
|
+
- docs/screenshots/admin2.jpg
|
|
98
|
+
- docs/screenshots/admin3.jpg
|
|
99
|
+
- docs/screenshots/admin4.jpg
|
|
100
|
+
- docs/screenshots/admin5.png
|
|
101
|
+
- docs/screenshots/admin6.png
|
|
102
|
+
- docs/screenshots/filtered.png
|
|
103
|
+
- docs/screenshots/main.png
|
|
104
|
+
- docs/screenshots/ransack1.png
|
|
105
|
+
- docs/screenshots/ransack2.png
|
|
106
|
+
- docs/screenshots/ransack3.png
|
|
107
|
+
- docs/screenshots/search.png
|
|
108
|
+
- docs/screenshots/theme_blue_sky_basin.png
|
|
109
|
+
- docs/widget-list-demo-thumbnail.png
|
|
96
110
|
- lib/extensions/action_controller_base.rb
|
|
97
111
|
- lib/widget_list.rb
|
|
98
112
|
- lib/widget_list/engine.rb
|