extjs_scaffold 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ });