extjs_scaffold 0.1.1

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.
Files changed (101) hide show
  1. data/.gitignore +9 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +80 -0
  6. data/Rakefile +28 -0
  7. data/extjs_scaffold.gemspec +27 -0
  8. data/features/scaffold_generator.feature +124 -0
  9. data/features/step_definitions/aruba_ext_steps.rb +6 -0
  10. data/features/support/setup.rb +5 -0
  11. data/lib/extjs_scaffold.rb +1 -0
  12. data/lib/extjs_scaffold/version.rb +3 -0
  13. data/lib/generators/extjs_scaffold.rb +15 -0
  14. data/lib/generators/extjs_scaffold/install/USAGE +28 -0
  15. data/lib/generators/extjs_scaffold/install/install_generator.rb +82 -0
  16. data/lib/generators/extjs_scaffold/install/templates/Actionable.js +27 -0
  17. data/lib/generators/extjs_scaffold/install/templates/App.js +11 -0
  18. data/lib/generators/extjs_scaffold/install/templates/EditWindow.js +135 -0
  19. data/lib/generators/extjs_scaffold/install/templates/FormPanel.js +27 -0
  20. data/lib/generators/extjs_scaffold/install/templates/Format.js +34 -0
  21. data/lib/generators/extjs_scaffold/install/templates/GridPanel.js +289 -0
  22. data/lib/generators/extjs_scaffold/install/templates/ParentComboField.js +39 -0
  23. data/lib/generators/extjs_scaffold/install/templates/Rails.js +162 -0
  24. data/lib/generators/extjs_scaffold/install/templates/ScrollingToolbar.js +170 -0
  25. data/lib/generators/extjs_scaffold/install/templates/SearchField.js +104 -0
  26. data/lib/generators/extjs_scaffold/install/templates/UpdateWindow.js +112 -0
  27. data/lib/generators/extjs_scaffold/install/templates/Updateable.js +31 -0
  28. data/lib/generators/extjs_scaffold/install/templates/ext_auth.html.erb +3 -0
  29. data/lib/generators/extjs_scaffold/install/templates/extjs_scaffold.css.scss +9 -0
  30. data/lib/generators/extjs_scaffold/install/templates/images/README.txt +1 -0
  31. data/lib/generators/extjs_scaffold/install/templates/images/add.gif +0 -0
  32. data/lib/generators/extjs_scaffold/install/templates/images/application_form_edit.png +0 -0
  33. data/lib/generators/extjs_scaffold/install/templates/images/delete.gif +0 -0
  34. data/lib/generators/extjs_scaffold/install/templates/images/tick.png +0 -0
  35. data/lib/generators/extjs_scaffold/scaffold/USAGE +24 -0
  36. data/lib/generators/extjs_scaffold/scaffold/scaffold_generator.rb +19 -0
  37. data/lib/generators/extjs_scaffold/scaffold_controller/USAGE +20 -0
  38. data/lib/generators/extjs_scaffold/scaffold_controller/scaffold_controller_generator.rb +296 -0
  39. data/lib/generators/extjs_scaffold/scaffold_controller/templates/controller.rb +191 -0
  40. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/Controller.js +53 -0
  41. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/EditForm.js +17 -0
  42. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/EditWindow.js +27 -0
  43. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/Grid.js +26 -0
  44. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/Model.js +43 -0
  45. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/ReferenceStore.js +27 -0
  46. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/Store.js +28 -0
  47. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/UpdateForm.js +17 -0
  48. data/lib/generators/extjs_scaffold/scaffold_controller/templates/js/UpdateWindow.js +21 -0
  49. data/lib/generators/extjs_scaffold/scaffold_controller/templates/model.rb +57 -0
  50. data/lib/generators/extjs_scaffold/scaffold_controller/templates/tests/controller_spec.rb +197 -0
  51. data/lib/generators/extjs_scaffold/scaffold_controller/templates/tests/controller_test.rb +85 -0
  52. data/lib/generators/extjs_scaffold/scaffold_controller/templates/views/erb/index.html.erb +3 -0
  53. data/lib/generators/extjs_scaffold/scaffold_controller/templates/views/haml/index.html.haml +3 -0
  54. data/spec/dummy/.gitignore +15 -0
  55. data/spec/dummy/README +261 -0
  56. data/spec/dummy/Rakefile +7 -0
  57. data/spec/dummy/app/assets/images/rails.png +0 -0
  58. data/spec/dummy/app/assets/javascripts/application.js +7 -0
  59. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  60. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  61. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  62. data/spec/dummy/app/mailers/.gitkeep +0 -0
  63. data/spec/dummy/app/models/.gitkeep +0 -0
  64. data/spec/dummy/app/views/layouts/application.html.erb +16 -0
  65. data/spec/dummy/config.ru +4 -0
  66. data/spec/dummy/config/application.rb +48 -0
  67. data/spec/dummy/config/boot.rb +7 -0
  68. data/spec/dummy/config/database.yml +25 -0
  69. data/spec/dummy/config/environment.rb +5 -0
  70. data/spec/dummy/config/environments/development.rb +30 -0
  71. data/spec/dummy/config/environments/production.rb +60 -0
  72. data/spec/dummy/config/environments/test.rb +39 -0
  73. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  74. data/spec/dummy/config/initializers/inflections.rb +10 -0
  75. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  76. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  77. data/spec/dummy/config/initializers/session_store.rb +8 -0
  78. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  79. data/spec/dummy/config/locales/en.yml +5 -0
  80. data/spec/dummy/config/routes.rb +58 -0
  81. data/spec/dummy/db/schema.rb +23 -0
  82. data/spec/dummy/db/seeds.rb +7 -0
  83. data/spec/dummy/doc/README_FOR_APP +2 -0
  84. data/spec/dummy/lib/assets/.gitkeep +0 -0
  85. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  86. data/spec/dummy/log/.gitkeep +0 -0
  87. data/spec/dummy/public/404.html +26 -0
  88. data/spec/dummy/public/422.html +26 -0
  89. data/spec/dummy/public/500.html +26 -0
  90. data/spec/dummy/public/favicon.ico +0 -0
  91. data/spec/dummy/public/index.html +241 -0
  92. data/spec/dummy/public/robots.txt +5 -0
  93. data/spec/dummy/script/rails +6 -0
  94. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  95. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  96. data/spec/generators/install_spec.rb +140 -0
  97. data/spec/generators/scaffold_spec.rb +244 -0
  98. data/spec/spec_helper.rb +26 -0
  99. data/spec/support/App.js +12 -0
  100. data/spec/support/rails_routes.rb +4 -0
  101. metadata +290 -0
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @author Mark H Winkler
3
+ * @class App.ux.form.field.ParentCombo
4
+ * @extends Ext.form.field.ComboBox
5
+ * <p>Extends ComboBox to create a base class for parent
6
+ * record associations in detail forms. Uses valueField = 'id', displayField = 'name</p>
7
+ * <pre><code>
8
+ Ext.create('Ext.form.Panel', {
9
+ items: [{
10
+ xtype: 'parentcombo',
11
+ store: Ext.data.StoreManager.lookup('store')
12
+ }]
13
+ });
14
+
15
+ Ext.create('App.ux.form.field.ParentCombo', {
16
+ store: Ext.data.StoreManager.lookup('store')
17
+ });
18
+ </code></pre>
19
+ */
20
+ Ext.define('<%= app_name %>.ux.form.field.ParentCombo', {
21
+ extend: 'Ext.form.field.ComboBox',
22
+ alias: 'widget.parentcombo',
23
+
24
+ valueField: 'id',
25
+ displayField:'name',
26
+ typeAhead: false,
27
+ selectOnFocus: true,
28
+ loadingText: 'Searching...',
29
+ hideTrigger:true,
30
+ forceSelection: true,
31
+ allowBlank: true,
32
+ minChars: 2,
33
+ lazyRender: true,
34
+ emptyText: 'type at least 2 characters from name',
35
+ width: 350,
36
+ listWidth: 350,
37
+ listClass: 'x-combo-list-small',
38
+ triggerClass:'x-form-search-trigger'
39
+ });
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @author Mark H Winkler
3
+ * @class App.ux.data.proxy.Rails
4
+ * @extends Ext.data.proxy.Rest
5
+ *
6
+ * Rails proxy extends Rest proxy to allow non-rest actions to be used.
7
+ * Example:
8
+ * POST /teams/delete_all.json (collection)
9
+ * POST /teams/1/send_note.json (member)
10
+ */
11
+ Ext.define('<%= app_name %>.ux.data.proxy.Rails', {
12
+ extend: 'Ext.data.proxy.Rest',
13
+ alias : 'proxy.rails',
14
+
15
+ /**
16
+ * @config: addActions
17
+ * config of allowed actions
18
+ *
19
+ * addActions: {
20
+ * destroy_all: {
21
+ * method: 'POST',
22
+ * collection: true
23
+ * }
24
+ * }
25
+ */
26
+ addActions: {},
27
+
28
+ /**
29
+ * @function: doAction(action, records, options)
30
+ * allows a non rest action to be passed
31
+ * to Rails (e.g. /teams/delete_all.json).
32
+ *
33
+ * The format and fields sent are determined in the proxy writer.
34
+ * the following will send .json => player [{id: 1},{id:2}]
35
+ * writer: {
36
+ * type: 'json',
37
+ * root: 'player',
38
+ * encode: true,
39
+ * writeAllFields: false,
40
+ * allowSingle: false
41
+ * }
42
+ *
43
+ * The actionName must exist in the proxy under the 'addActions' config which stores
44
+ * the METHOD (GET, POST, PUT, DELETE) and Collection (true = collection or false = member)
45
+ *
46
+ * When collection = false the record id is sent in query string: /teams/1/change_something.json
47
+ *
48
+ * params:
49
+ * action (string) - required - name of action added to proxy
50
+ * records (array) - optional - array of Model Records
51
+ * options (object) - optional - options to associate with action including callback
52
+ *
53
+ */
54
+ doAction: function(action, records, options) {
55
+ // create options object if not passed
56
+ options = Ext.apply({}, options);
57
+
58
+ // declare config vars
59
+ var me = this,
60
+ scope = options.scope || me,
61
+ operation,
62
+ callback;
63
+
64
+ // create records array if not passed
65
+ records = records || [];
66
+
67
+ // concat params into options object
68
+ Ext.apply(options, {
69
+ records: records,
70
+ action : action
71
+ });
72
+
73
+ // create a new operation to send to the proxy
74
+ operation = Ext.create('Ext.data.Operation', options);
75
+
76
+ // create a callback chain for the action
77
+ callback = function(operation) {
78
+ if (operation.wasSuccessful()) {
79
+ Ext.callback(options.success, scope, [operation]);
80
+ } else {
81
+ Ext.callback(options.failure, scope, [operation]);
82
+ }
83
+ Ext.callback(options.callback, scope, [operation]);
84
+ };
85
+
86
+ // call doRequest
87
+ me.doRequest(operation, callback, me);
88
+ return me;
89
+ },
90
+
91
+ /**
92
+ * @function: getActionMethod(request)
93
+ * Returns the method from addActions config
94
+ * called from getMethod
95
+ */
96
+ getActionMethod: function(request) {
97
+ var action = this.addActions[request.action];
98
+ if (action) {
99
+ return action['method'] || 'POST';
100
+ }
101
+ return null;
102
+ },
103
+
104
+ /**
105
+ * Extending Ext.data.proxy.Ajax.getMethod() to return addActions
106
+ */
107
+ getMethod: function(request) {
108
+ return this.callParent(arguments) || this.getActionMethod(request);
109
+ },
110
+
111
+ /**
112
+ * Overriding buildUrl - incorporates the {@link #appendId} and {@link #format} options from Rest proxy
113
+ * uses addActions object to append custom actions sent to controller
114
+ * cache buster string from Server proxy is appended instead of calling parent
115
+ */
116
+ buildUrl: function(request) {
117
+ var me = this,
118
+ operation = request.operation,
119
+ records = operation.records || [],
120
+ record = records[0],
121
+ format = me.format,
122
+ url = me.getUrl(request),
123
+ id = record ? record.getId() : operation.id;
124
+
125
+ // clear id if addActions type is collection
126
+ if (me.addActions[request.action]) {
127
+ if (me.addActions[request.action].collection) {
128
+ id = null;
129
+ }
130
+ }
131
+
132
+ if (me.appendId && id) {
133
+ if (!url.match(/\/$/)) {
134
+ url += '/';
135
+ }
136
+ url += id;
137
+ }
138
+
139
+ // if part of custom actions, add to url
140
+ if (me.addActions[request.action]) {
141
+ if (!url.match(/\/$/)) {
142
+ url += '/';
143
+ }
144
+ url += request.action;
145
+ }
146
+
147
+ if (format) {
148
+ if (!url.match(/\.$/)) {
149
+ url += '.';
150
+ }
151
+ url += format;
152
+ }
153
+
154
+ request.url = url;
155
+
156
+ // adding cache buster string from Ext.data.proxy.Server
157
+ if (me.noCache) {
158
+ url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.cacheString, Ext.Date.now()));
159
+ }
160
+ return url;
161
+ }
162
+ });
@@ -0,0 +1,170 @@
1
+ /**
2
+ * @author Mark H Winkler
3
+ * @class App.ux.toolbar.Scrolling
4
+ * @extends Ext.toolbar.Toolbar
5
+ * <p>Extends toolbar.Toolbar</p>
6
+ * <p>Stripped down version of Ext.toolbar.Paging that shows total recs from store</p>
7
+ */
8
+ Ext.define('<%= app_name %>.ux.toolbar.Scrolling', {
9
+ extend: 'Ext.toolbar.Toolbar',
10
+ alias: 'widget.scrollingtoolbar',
11
+ requires: ['Ext.toolbar.TextItem'],
12
+ /**
13
+ * @cfg {String} displayMsg
14
+ * The paging status message to display
15
+ */
16
+ displayMsg : 'Total: {0}',
17
+ /**
18
+ * @cfg {String} emptyMsg
19
+ * The message to display when no records are found (defaults to 'No data to display')
20
+ */
21
+ emptyMsg : 'No data to display',
22
+ /**
23
+ * @cfg {String} refreshText
24
+ * The quicktip text displayed for the Refresh button (defaults to <tt>'Refresh'</tt>).
25
+ * <b>Note</b>: quick tips must be initialized for the quicktip to show.
26
+ */
27
+ refreshText : 'Refresh',
28
+ /**
29
+ * @cfg {boolean} displayReload
30
+ * add reload button to toolbar
31
+ */
32
+ displayReload: false,
33
+
34
+ initComponent : function(){
35
+ var me = this;
36
+ me.items = [];
37
+
38
+ if (me.displayReload) {
39
+ me.items.push({
40
+ tooltip: 'Refresh',
41
+ iconCls: 'x-tbar-loading',
42
+ scope: me,
43
+ handler: me.reload
44
+ });
45
+ }
46
+
47
+ if (me.displayInfo) {
48
+ me.items.push('->');
49
+ me.items.push({xtype: 'tbtext', itemId: 'displayItem'});
50
+ }
51
+
52
+ me.callParent();
53
+
54
+ me.on('afterlayout', me.onLoad, me, {single: true});
55
+
56
+ me.bindStore(me.store || 'ext-empty-store', true);
57
+ },
58
+
59
+ // private
60
+ updateInfo : function(){
61
+ var me = this,
62
+ displayItem = me.child('#displayItem'),
63
+ store = me.store,
64
+ totalCount = store.getTotalCount();
65
+
66
+ if (displayItem) {
67
+ count = store.getCount();
68
+ if (count === 0) {
69
+ msg = me.emptyMsg;
70
+ } else {
71
+ msg = Ext.String.format(
72
+ me.displayMsg,
73
+ totalCount
74
+ );
75
+ }
76
+ displayItem.setText(msg);
77
+ me.doComponentLayout();
78
+ }
79
+ },
80
+
81
+ // private
82
+ onLoad : function(){
83
+ var me = this;
84
+
85
+ if (!me.rendered) {
86
+ return;
87
+ }
88
+ me.updateInfo();
89
+ },
90
+
91
+ // private
92
+ onLoadError : function(){
93
+ if (!this.rendered) {
94
+ return;
95
+ }
96
+ this.child('#refresh').enable();
97
+ },
98
+
99
+ /**
100
+ * Refresh the current page, has the same effect as clicking the 'refresh' button.
101
+ */
102
+ // doRefresh : function(){
103
+ // var me = this,
104
+ // current = me.store.currentPage;
105
+ //
106
+ // if (me.fireEvent('beforechange', me, current) !== false) {
107
+ // me.store.loadPage(current);
108
+ // }
109
+ // },
110
+
111
+ /**
112
+ * Binds the paging toolbar to the specified {@link Ext.data.Store}
113
+ * @param {Ext.data.Store} store The store to bind to this toolbar
114
+ * @param {Boolean} initial (Optional) true to not remove listeners
115
+ */
116
+ bindStore : function(store, initial){
117
+ var me = this;
118
+
119
+ if (!initial && me.store) {
120
+ if (store !== me.store && me.store.autoDestroy) {
121
+ me.store.destroy();
122
+ } else {
123
+ me.store.un('load', me.onLoad, me);
124
+ me.store.un('exception', me.onLoadError, me);
125
+ }
126
+ if (!store) {
127
+ me.store = null;
128
+ }
129
+ }
130
+ if (store) {
131
+ store = Ext.data.StoreManager.lookup(store);
132
+ store.on({
133
+ scope: me,
134
+ load: me.onLoad,
135
+ exception: me.onLoadError
136
+ });
137
+ }
138
+ me.store = store;
139
+ },
140
+
141
+ // private
142
+ onDestroy : function(){
143
+ this.bindStore(null);
144
+ this.callParent();
145
+ },
146
+
147
+ updateTotal: function(total){
148
+ var me = this,
149
+ displayItem = me.child('#displayItem');
150
+
151
+ if (displayItem) {
152
+ count = total;
153
+ if (count === 0) {
154
+ msg = me.emptyMsg;
155
+ } else {
156
+ msg = Ext.String.format(
157
+ me.displayMsg,
158
+ count
159
+ );
160
+ }
161
+ displayItem.setText(msg);
162
+ me.doComponentLayout();
163
+ }
164
+ },
165
+
166
+ reload: function() {
167
+ var me = this;
168
+ me.store.load();
169
+ }
170
+ });
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @author Adapted from Ext.ux.form.SearchField example
3
+ * http://www.sencha.com/
4
+ * @class App.ux.form.field.SearchField
5
+ * @extends Ext.form.field.Trigger
6
+ * <p>Extends Triggers with an assoicated data store,
7
+ * passing the entered text as an extra parameter to the store
8
+ * For example:</p>
9
+ * <pre><code>
10
+ Ext.create('Ext.grid.Panel', {
11
+ dockedItems: [{
12
+ xtype: 'toolbar',
13
+ dock: 'top',
14
+ items: [{
15
+ xtype: 'searchfield',
16
+ store: Ext.data.StoreManager.lookup('store')
17
+ }]
18
+ }]
19
+ });
20
+
21
+ Ext.create('App.ux.form.field.SearchField', {
22
+ store: Ext.data.StoreManager.lookup('store')
23
+ });
24
+ </code></pre>
25
+ */
26
+ Ext.define('<%= app_name %>.ux.form.field.SearchField', {
27
+ extend: 'Ext.form.field.Trigger',
28
+ alias: 'widget.searchfield',
29
+
30
+ trigger1Cls: 'x-form-clear-trigger',
31
+ trigger2Cls: 'x-form-search-trigger',
32
+
33
+ emptyText: '',
34
+ width: 180,
35
+
36
+ /**
37
+ * @cfg {store} store
38
+ * The associated data store to receive query
39
+ */
40
+ store: '',
41
+
42
+ /**
43
+ * @cfg {String} queryParam
44
+ * The query param name sent to store
45
+ * (defaults to <tt>query</tt>)
46
+ */
47
+ queryParam: 'query',
48
+
49
+ initComponent: function(){
50
+ this.callParent(arguments);
51
+ this.on('specialkey', this.checkEnterKey, this);
52
+ },
53
+
54
+ onRender: function() {
55
+ this.callParent(arguments);
56
+ this.triggerEl.elements[0].setDisplayed('none');
57
+ },
58
+
59
+ // Handle enter key presses, execute the search if the field has a value
60
+ checkEnterKey: function(field, e) {
61
+ var value = this.getValue();
62
+ if (e.getKey() === e.ENTER) {
63
+ this.search();
64
+ }
65
+ },
66
+
67
+ onTrigger2Click: function() {
68
+ this.search();
69
+ },
70
+
71
+ onTrigger1Click: function() {
72
+ this.clearSearch();
73
+ },
74
+
75
+ search: function() {
76
+ var me = this;
77
+ me.triggerEl.elements[0].setDisplayed('block');
78
+ var v = this.getRawValue();
79
+ if (v.length < 1){
80
+ me.clearSearch();
81
+ return;
82
+ }
83
+ if (me.store) {
84
+ var query = {}
85
+ query[me.queryParam] = v;
86
+ Ext.apply(me.store.proxy.extraParams, query);
87
+ me.store.load();
88
+ }
89
+ me.doComponentLayout();
90
+ },
91
+
92
+ clearSearch: function() {
93
+ var me = this;
94
+ me.triggerEl.elements[0].setDisplayed('none');
95
+ me.setValue('');
96
+ if (me.store) {
97
+ var query = {}
98
+ query[me.queryParam] = '';
99
+ Ext.apply(me.store.proxy.extraParams, query);
100
+ me.store.load();
101
+ }
102
+ me.doComponentLayout();
103
+ }
104
+ });