fae-rails 2.1.0 → 2.2.0

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/app/assets/javascripts/fae/_deploy.js +198 -0
  4. data/app/assets/javascripts/fae/_modals.js +94 -0
  5. data/app/assets/javascripts/fae/application.js +2 -0
  6. data/app/assets/javascripts/fae/form/_ajax.js +4 -2
  7. data/app/assets/javascripts/fae/form/_filtering.js +34 -0
  8. data/app/assets/javascripts/fae/form/_form.js +1 -0
  9. data/app/assets/javascripts/fae/form/_form_manager.js +295 -0
  10. data/app/assets/javascripts/fae/form/_slugger.js.erb +2 -2
  11. data/app/assets/javascripts/fae/form/inputs/_select.js +5 -2
  12. data/app/assets/stylesheets/fae/base.scss +5 -2
  13. data/app/assets/stylesheets/fae/globals/imports/_variables.scss +1 -0
  14. data/app/assets/stylesheets/fae/globals/layout/_base.scss +7 -2
  15. data/app/assets/stylesheets/fae/globals/layout/_content-header.scss +8 -2
  16. data/app/assets/stylesheets/fae/globals/navigation/_header.scss +2 -2
  17. data/app/assets/stylesheets/fae/globals/navigation/_multi-col-subnav.scss +50 -0
  18. data/app/assets/stylesheets/fae/modules/_buttons.scss +11 -0
  19. data/app/assets/stylesheets/fae/modules/_deploy.scss +25 -0
  20. data/app/assets/stylesheets/fae/modules/_modal.scss +25 -0
  21. data/app/assets/stylesheets/fae/modules/_toggles.scss +39 -23
  22. data/app/assets/stylesheets/fae/modules/forms/_asset-actions.scss +1 -1
  23. data/app/assets/stylesheets/fae/modules/forms/_base.scss +1 -1
  24. data/app/assets/stylesheets/fae/modules/forms/_checkbox.scss +1 -1
  25. data/app/assets/stylesheets/fae/modules/forms/_date.scss +16 -0
  26. data/app/assets/stylesheets/fae/modules/forms/_form-manager.scss +82 -0
  27. data/app/assets/stylesheets/fae/modules/forms/_radio.scss +1 -1
  28. data/app/assets/stylesheets/fae/modules/forms/_select.scss +7 -6
  29. data/app/assets/stylesheets/fae/modules/forms/_simple-mde.scss +1 -1
  30. data/app/assets/stylesheets/fae/modules/forms/_textarea.scss +1 -1
  31. data/app/assets/stylesheets/fae/modules/tables/_filters.scss +4 -0
  32. data/app/assets/stylesheets/fae/pages/_login.scss +4 -0
  33. data/app/controllers/fae/application_controller.rb +7 -0
  34. data/app/controllers/fae/base_controller.rb +5 -1
  35. data/app/controllers/fae/deploy_controller.rb +24 -0
  36. data/app/controllers/fae/deploy_hooks_controller.rb +71 -0
  37. data/app/controllers/fae/form_managers_controller.rb +19 -0
  38. data/app/controllers/fae/options_controller.rb +1 -0
  39. data/app/controllers/fae/static_pages_controller.rb +6 -1
  40. data/app/controllers/fae/users_controller.rb +11 -1
  41. data/app/controllers/fae/utilities_controller.rb +18 -6
  42. data/app/helpers/fae/application_helper.rb +26 -1
  43. data/app/helpers/fae/form_helper.rb +26 -2
  44. data/app/helpers/fae/view_helper.rb +22 -9
  45. data/app/models/concerns/fae/base_model_concern.rb +9 -0
  46. data/app/models/fae/change.rb +19 -6
  47. data/app/models/fae/deploy_hook.rb +12 -0
  48. data/app/models/fae/form_manager.rb +24 -0
  49. data/app/models/fae/user.rb +2 -2
  50. data/app/services/fae/netlify_api.rb +197 -0
  51. data/app/views/devise/unlocks/new.html.slim +5 -9
  52. data/app/views/fae/application/_content_form.html.slim +16 -11
  53. data/app/views/fae/application/_file_uploader.html.slim +7 -2
  54. data/app/views/fae/application/_global_search_results.html.slim +1 -1
  55. data/app/views/fae/application/_header.slim +4 -1
  56. data/app/views/fae/application/_mobilenav.slim +3 -0
  57. data/app/views/fae/deploy/index.html.slim +40 -0
  58. data/app/views/fae/deploy_hooks/_form.html.slim +18 -0
  59. data/app/views/fae/deploy_hooks/_table.html.slim +28 -0
  60. data/app/views/fae/deploy_hooks/edit.html.slim +3 -0
  61. data/app/views/fae/deploy_hooks/new.html.slim +3 -0
  62. data/app/views/fae/images/_image_uploader.html.slim +12 -3
  63. data/app/views/fae/options/_form.html.slim +4 -1
  64. data/app/views/fae/pages/activity_log.html.slim +7 -3
  65. data/app/views/fae/pages/home.html.slim +3 -4
  66. data/app/views/fae/shared/_form_header.html.slim +16 -12
  67. data/app/views/fae/shared/_nested_table.html.slim +4 -2
  68. data/app/views/fae/shared/_recent_changes.html.slim +1 -1
  69. data/app/views/fae/shared/_shared_nested_table.html.slim +4 -1
  70. data/app/views/layouts/fae/application.html.slim +1 -0
  71. data/config/deploy.rb +3 -1
  72. data/config/initializers/devise.rb +6 -6
  73. data/config/locales/fae.en.yml +39 -3
  74. data/config/locales/fae.zh-CN.yml +2 -2
  75. data/config/routes.rb +9 -1
  76. data/db/migrate/20140809222030_add_user_table.rb +1 -1
  77. data/db/migrate/20190925153222_create_fae_form_managers.rb +11 -0
  78. data/db/migrate/20220118192729_create_fae_publish_hooks.rb +10 -0
  79. data/db/migrate/20220128133730_rename_publish_hooks.rb +5 -0
  80. data/db/migrate/20220202153607_add_position_to_deploy_hooks.rb +6 -0
  81. data/lib/fae/options.rb +4 -2
  82. data/lib/fae/version.rb +1 -1
  83. data/lib/generators/fae/base_generator.rb +11 -1
  84. data/lib/generators/fae/nested_scaffold_generator.rb +13 -0
  85. data/lib/generators/fae/templates/assets/fae.js +1 -1
  86. data/lib/generators/fae/templates/controllers/nested_scaffold_controller.rb +14 -0
  87. data/lib/generators/fae/templates/initializers/fae.rb +16 -1
  88. data/lib/generators/fae/templates/views/_form.html.slim +10 -1
  89. data/lib/generators/fae/templates/views/_form_index_nested.html.slim +15 -1
  90. data/lib/generators/fae/templates/views/_form_nested.html.slim +19 -2
  91. data/lib/generators/fae/templates/views/static_page_form.html.slim +13 -1
  92. metadata +28 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 64efa885d567372d041fc98081e6074e37adb03a
4
- data.tar.gz: 9945edf6077be0c1ef698a593da299c422baeb60
3
+ metadata.gz: 627ef0b4fdd41a840e63ef13d5816702d67109e3
4
+ data.tar.gz: 2ee2bdb673debee82c40eb3064d44fdaf0143515
5
5
  SHA512:
6
- metadata.gz: ab50aeecbc77980ccb20b73c742ef4043b74319b658a4e01f5a88432f538f95896e18bdf87cfdfee55331026d03283315e4b6ff1f1f8738274bc869a458f3bc9
7
- data.tar.gz: 48c3aae1f2cde1deb1405161f4942328c417733bf2832bac73fc4ca6967d96c30a0a8dfe994121c19e14631bdaabad28f721c9d4be82bdb099343bfff04f1947
6
+ metadata.gz: 3b31bb1dce450aecd010f337e851fb895ef86c4ccbcc8983d77e7d594e72a28e457a9966d79f238963d8e45fcb32a539167cd2e29666d2c6fb8a7b908cf8e41b
7
+ data.tar.gz: 0d9775d7d639bc6fbe66ffbfb40ca5aaf1dccf99344c6160fbbdc6e2f7116e57f42bcc0da4b81345d7f504c2fa89fb206bc9235393f9913f14f3955fe6745e16
data/README.md CHANGED
@@ -27,7 +27,7 @@ $ rails g fae:install
27
27
 
28
28
  ## Documentation
29
29
 
30
- For full documentation visit:
30
+ For full documentation visit:
31
31
  https://www.faecms.com/documentation
32
32
 
33
33
  ### Topics
@@ -57,6 +57,8 @@ https://www.faecms.com/documentation
57
57
  * [Change Tracker](docs/features/change_tracker.md)
58
58
  * [Slugger](docs/features/slugger.md)
59
59
  * [Disabling Environments](docs/features/disable_envs.md)
60
+ * [Form Field Label & Helper Text Manager](docs/features/form_manager.md)
61
+ * [Netlify Deploy Monitor](docs/features/netlify.md)
60
62
 
61
63
 
62
64
  ### Tutorials
@@ -0,0 +1,198 @@
1
+
2
+ /* global Fae, modal, FCH */
3
+
4
+ /**
5
+ * Fae deploy
6
+ * @namespace
7
+ */
8
+
9
+ Fae.deploy = {
10
+
11
+ ready: function() {
12
+ if (!$('body').hasClass('deploy')) return false;
13
+ this.$deployButtons = $('.js-run-deploy');
14
+ this.deployFinished = true;
15
+ this.buttonsEnabled = true;
16
+ this.pollTimeout = null;
17
+ this.pollInterval = 5000;
18
+ this.idleStates = ['ready', 'error']
19
+
20
+ this.pollDeployStatus();
21
+ this.deployButtonListener();
22
+ this.documentFocusListener();
23
+ this.notifyIdle();
24
+ this.refreshDeploysListAndStatuses();
25
+ },
26
+
27
+ deployButtonListener: function() {
28
+ var _this = this;
29
+ _this.$deployButtons.click(function(e) {
30
+ e.preventDefault();
31
+ _this.disableButtons();
32
+ var deploy_hook_type = $(this).data('build-hook-type');
33
+ $.post( '/admin/deploy/deploy_site', { deploy_hook_type: deploy_hook_type }, function(data) {
34
+ // Netlify returns nothing for deploy hook posts
35
+ });
36
+ });
37
+ },
38
+
39
+ documentFocusListener: function() {
40
+ var _this = this;
41
+ document.addEventListener('visibilitychange', function(ev) {
42
+ if (document.visibilityState === 'visible') {
43
+ _this.pollDeployStatus();
44
+ } else if (document.visibilityState === 'hidden') {
45
+ _this.destroyPoll();
46
+ }
47
+ });
48
+ },
49
+
50
+ refreshDeploysListAndStatuses: function() {
51
+ var _this = this;
52
+ $.get('/admin/deploy/deploys_list', function (data) {
53
+ if (data) {
54
+ _this.drawTables(data);
55
+ _this.stateChecks(data);
56
+ }
57
+ });
58
+ },
59
+
60
+ pollDeployStatus: function() {
61
+ var _this = this;
62
+ function poll() {
63
+ _this.refreshDeploysListAndStatuses();
64
+ _this.pollTimeout = setTimeout(poll, _this.pollInterval);
65
+ }
66
+ poll();
67
+ },
68
+
69
+ destroyPoll: function() {
70
+ clearTimeout(this.pollTimeout);
71
+ },
72
+
73
+ notifyRunning: function() {
74
+ $('.deploying-heading').addClass('running');
75
+ $('#js-deploying-section').removeClass('hidden');
76
+ },
77
+
78
+ notifyIdle: function() {
79
+ $('.deploying-heading').removeClass('running');
80
+ $('#js-deploying-section').addClass('hidden');
81
+ },
82
+
83
+ enableButtons: function() {
84
+ var _this = this;
85
+ if (!_this.buttonsEnabled) {
86
+ _this.buttonsEnabled = true;
87
+ _this.$deployButtons.prop('disabled', false);
88
+ }
89
+ },
90
+
91
+ disableButtons: function() {
92
+ var _this = this;
93
+ if (_this.buttonsEnabled) {
94
+ _this.buttonsEnabled = false;
95
+ _this.$deployButtons.prop('disabled', true);
96
+ }
97
+ },
98
+
99
+ afterDeploy: function() {
100
+ var _this = this;
101
+ if (!_this.deployFinished) {
102
+ _this.notifyIdle();
103
+ _this.enableButtons();
104
+ _this.deployFinished = true;
105
+ }
106
+ },
107
+
108
+ drawTables: function(data) {
109
+ var _this = this;
110
+ var runningDeploys = _this.getRunningDeploys(data);
111
+ var pastDeploys = _this.getPastDeploys(data);
112
+ $('.js-deploys-list').find('tbody').find('tr').remove();
113
+ _this.injectTableDeployData(runningDeploys, $('.js-deploys-list.running').find('tbody'));
114
+ _this.injectTableDeployData(pastDeploys, $('.js-deploys-list.past').find('tbody'));
115
+ Fae.navigation.lockFooter();
116
+ },
117
+
118
+ getRunningDeploys: function(data) {
119
+ var _this = this;
120
+ return data.filter(function(deploy) {
121
+ return $.inArray(deploy.state, _this.idleStates) === -1;
122
+ });
123
+ },
124
+
125
+ getPastDeploys: function(data) {
126
+ var _this = this;
127
+ return data.filter(function(deploy) {
128
+ return $.inArray(deploy.state, _this.idleStates) !== -1;
129
+ });
130
+ },
131
+
132
+ injectTableDeployData: function(deploys, $tbody) {
133
+ var _this = this;
134
+ $.each(deploys, function(i, deploy) {
135
+ $tbody.append(
136
+ $('<tr>').append([
137
+ $('<td>').text(deploy.commit_ref !== null ? 'FINE dev update' : deploy.title),
138
+ $('<td>').text(moment(deploy.updated_at).format('MM/DD/YYYY h:mm a')),
139
+ $('<td>').text(_this.deployDuration(deploy)),
140
+ $('<td>').text(_this.deployEnvironment(deploy)),
141
+ $('<td>').html(_this.errorMsg(deploy)),
142
+ ])
143
+ );
144
+ });
145
+ },
146
+
147
+ stateChecks: function(data) {
148
+ var _this = this;
149
+ if (_this.deployIsRunning(data)) {
150
+ _this.notifyRunning();
151
+ _this.disableButtons();
152
+ _this.deployFinished = false;
153
+ } else {
154
+ _this.afterDeploy();
155
+ }
156
+ },
157
+
158
+ valCheck: function(val) {
159
+ if (val !== null) return val;
160
+ },
161
+
162
+ deployIsRunning: function(data) {
163
+ var _this = this;
164
+ var running = false;
165
+ $.each(data, function(i, deploy) {
166
+ if(_this.idleStates.indexOf(deploy.state) === -1) {
167
+ running = true;
168
+ return false;
169
+ }
170
+ });
171
+ return running;
172
+ },
173
+
174
+ deployDuration: function(deploy) {
175
+ if (deploy.deploy_time === null) {
176
+ return '–';
177
+ } else {
178
+ return moment.utc(parseInt(deploy.deploy_time)*1000).format('HH:mm:ss');
179
+ }
180
+ },
181
+
182
+ deployEnvironment: function(deploy) {
183
+ if (deploy.branch === 'master' || deploy.branch === 'main') {
184
+ return 'Production';
185
+ }
186
+ return deploy.branch.charAt(0).toUpperCase() + deploy.branch.slice(1);
187
+ },
188
+
189
+ errorMsg: function(deploy) {
190
+ if (deploy.error_message) {
191
+ var out = 'An error occurred. Please contact your ';
192
+ out += '<a href="/admin/help">FINE team</a>.'
193
+ return out;
194
+ }
195
+ }
196
+
197
+ };
198
+
@@ -6,8 +6,19 @@
6
6
  */
7
7
  Fae.modals = {
8
8
  ready: function() {
9
+ this.$body = $('body');
10
+ this.openClass = 'modal-open';
11
+ this.modalClass = 'MODAL_ID-modal-open';
12
+ this.showEvent = 'modal:show';
13
+ this.shownEvent = 'modal:shown';
14
+ this.closeEvent = 'modal:close';
15
+ this.closedEvent = 'modal:closed';
16
+ this.modalOpen = false;
17
+
9
18
  this.imageModals();
10
19
  this.markdownModalListener();
20
+
21
+ this.ajaxModalListener();
11
22
  },
12
23
 
13
24
  /**
@@ -56,5 +67,88 @@ Fae.modals = {
56
67
  */
57
68
  markdownModalListener: function() {
58
69
  FCH.$document.on('click', '.markdown-support', this.markdownModal);
70
+ },
71
+
72
+ /**
73
+ * load remote data, open modal view
74
+ * @see {@link modals.formModalListener}
75
+ * @has_test {features/form_helpers/fae_input_spec.rb}
76
+ */
77
+ openAjaxModal: function (remoteUrl, relatedTarget) {
78
+ var _this = this;
79
+
80
+ $.get(remoteUrl, function (data) {
81
+ //Open remote url content in modal window
82
+ $(data).modal({
83
+ minHeight: "75%",
84
+ minWidth: "75%",
85
+ overlayClose: true,
86
+ zIndex: 1100,
87
+ containerId: "fae-modal",
88
+ persist: true,
89
+ opacity: 70,
90
+ overlayCss: { backgroundColor: "#000" },
91
+ onOpen: function (dialog) {
92
+ // Fade in modal + show data
93
+ dialog.overlay.fadeIn();
94
+ dialog.container.fadeIn(function() {
95
+ var shownEvent = $.Event(_this.shownEvent, { dialog: dialog, relatedTarget: relatedTarget });
96
+ _this.$body.trigger(shownEvent);
97
+ });
98
+ dialog.data.show();
99
+
100
+ var modalClasses = [_this.createClassFromModalId(relatedTarget.attr('id')), _this.openClass].join(' ');
101
+
102
+ _this.modalOpen = true;
103
+ _this.$body.addClass(modalClasses);
104
+ },
105
+ onShow: function (dialog) {
106
+ var showEvent = $.Event(_this.showEvent, { dialog: dialog, relatedTarget: relatedTarget });
107
+ _this.$body.trigger(showEvent);
108
+
109
+ $(dialog.container).css('height', 'auto')
110
+ },
111
+ onClose: function (dialog) {
112
+ var closeEvent = $.Event(_this.closeEvent, { dialog: dialog, relatedTarget: relatedTarget });
113
+ _this.$body.trigger(closeEvent);
114
+
115
+ // Fade out modal and close
116
+ dialog.container.fadeOut();
117
+ dialog.overlay.fadeOut(function () {
118
+ $.modal.close(); // must call this!
119
+
120
+ var closedEvent = $.Event(_this.closedEvent, { dialog: dialog, relatedTarget: relatedTarget });
121
+ var modalClasses = [_this.createClassFromModalId(relatedTarget.attr('id')), _this.openClass].join(' ');
122
+
123
+ _this.modalOpen = false;
124
+ _this.$body.removeClass(modalClasses);
125
+ _this.$body.trigger(closedEvent);
126
+ });
127
+ }
128
+ });
129
+
130
+ });
131
+ },
132
+
133
+ /**
134
+ * Click event listener for ajax modal links triggering specific view within modal popup
135
+ * @fires {@link modals.ajaxModal}
136
+ * @has_test {features/form_helpers/fae_input_spec.rb}
137
+ */
138
+ ajaxModalListener: function () {
139
+ var _this = this;
140
+
141
+ FCH.$document.on('click', '.js-fae-modal', function (e) {
142
+ e.preventDefault();
143
+ var $this = $(this);
144
+ var url = $this.attr('href');
145
+ var id = $this.attr('id');
146
+
147
+ _this.openAjaxModal(url, $this)
148
+ });
149
+ },
150
+
151
+ createClassFromModalId: function(modalId) {
152
+ return this.modalClass.replace('MODAL_ID', modalId);
59
153
  }
60
154
  };
@@ -46,6 +46,7 @@
46
46
  //= require fae/form/_cancel
47
47
  //= require fae/form/_ajax
48
48
  //= require fae/form/_filtering
49
+ //= require fae/form/_form_manager
49
50
  //= require fae/form/fae_chosen
50
51
  //= require fae/form/fileinputer
51
52
 
@@ -57,6 +58,7 @@
57
58
 
58
59
  //= require fae/_modals
59
60
  //= require fae/_tables
61
+ //= require fae/_deploy
60
62
 
61
63
  //= require fae
62
64
 
@@ -10,7 +10,6 @@ Fae.form.ajax = {
10
10
  init: function() {
11
11
  this.$addedit_form = $('.js-addedit-form, .js-index-addedit-form');
12
12
  this.$filter_form = $('.js-filter-form');
13
- this.$nested_form = $('.nested-form');
14
13
 
15
14
  this.addEditLinks();
16
15
  this.addEditSubmission();
@@ -67,6 +66,8 @@ Fae.form.ajax = {
67
66
  $wrapper.find('.input.file').fileinputer();
68
67
  }
69
68
 
69
+ this.$nested_form = $('.nested-form');
70
+
70
71
  // Bind validation to nested form fields added by AJAX
71
72
  Fae.form.validator.bindValidationEvents(this.$nested_form);
72
73
 
@@ -80,6 +81,7 @@ Fae.form.ajax = {
80
81
  Fae.form.text.initHTML();
81
82
  Fae.form.checkbox.setCheckboxAsActive();
82
83
  Fae.form.select.init();
84
+ Fae.form.formManager.setupAllFields($wrapper.find('form'));
83
85
 
84
86
  // validate nested form fields on submit
85
87
  Fae.form.validator.formValidate(this.$nested_form);
@@ -297,7 +299,7 @@ Fae.form.ajax = {
297
299
  * @todo Clean this up, moving listeners into their respective component classes (select, checkbox, etc.)
298
300
  */
299
301
  htmlListeners: function() {
300
- $('#js-main-content, .login-form > form')
302
+ $('#js-main-content, .login-form > form, #simplemodal-data')
301
303
 
302
304
  /**
303
305
  * For the delete button on file input
@@ -25,6 +25,7 @@ Fae.form.filtering = {
25
25
  }
26
26
 
27
27
  this.setFilterDropDowns();
28
+ this.setTextInputs();
28
29
  this.filterFormListeners();
29
30
  this.paginationListeners();
30
31
  this.sortingSetup();
@@ -87,6 +88,7 @@ Fae.form.filtering = {
87
88
  // update search param when form submits
88
89
  .on('submit', function(ev) {
89
90
  $('.js-reset-btn').show();
91
+ $('.js-reset-btn').removeClass('hidden');
90
92
  _this.updateFryrAndResetPaging('search', $('#filter_search').val());
91
93
  return false;
92
94
  })
@@ -117,6 +119,17 @@ Fae.form.filtering = {
117
119
  _this.updateFryrAndResetPaging(key, value);
118
120
 
119
121
  $('.js-reset-btn').show();
122
+ $('.js-reset-btn').removeClass('hidden');
123
+ })
124
+
125
+ // update hash when date inputs changed
126
+ .on('change', '.datepicker input', function() {
127
+ var key = $(this).attr('id').split('filter_')[1];
128
+ var value = $(this).val();
129
+ timer = setTimeout(function() {
130
+ _this.updateFryrAndResetPaging(key, value);
131
+ $('.js-reset-btn').show();
132
+ }, 500);
120
133
  });
121
134
  },
122
135
 
@@ -147,6 +160,27 @@ Fae.form.filtering = {
147
160
  $('.js-reset-btn').show();
148
161
  },
149
162
 
163
+ /**
164
+ * Sets filter dropdowns on page load based on Fryr params
165
+ */
166
+ setTextInputs: function() {
167
+ // Exit early if this.fry.params is blank
168
+ if ($.isEmptyObject(this.fry.params)) {
169
+ return;
170
+ }
171
+
172
+ // Loop through all available this.fry.params to find the select menu and the proper option
173
+ $.each(this.fry.params, function(key, value) {
174
+ var $input = $('.js-filter-form .table-filter-group.text-input #filter_' + key);
175
+
176
+ if($input.length) {
177
+ $input.val(decodeURIComponent(value));
178
+ }
179
+ });
180
+
181
+ $('.js-reset-btn').show();
182
+ },
183
+
150
184
  /**
151
185
  * Updates a Fryr param while reseting paging
152
186
  * Use for most cases of pushing a single params to Fryr, as paging will always reset in those cases
@@ -20,6 +20,7 @@ Fae.form = {
20
20
  this.ajax.init();
21
21
  this.filtering.init();
22
22
  this.slugger.init();
23
+ this.formManager.init();
23
24
 
24
25
  // input type=file customization
25
26
  // This doesn't work in IE. It's not worth figuring out why by this point. IE9 gets plain file uploader.