pageflow 15.1.1 → 15.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pageflow might be problematic. Click here for more details.

Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +337 -162
  3. data/README.md +1 -2
  4. data/admins/pageflow/accounts.rb +13 -35
  5. data/admins/pageflow/entry.rb +21 -1
  6. data/admins/pageflow/entry_templates.rb +140 -0
  7. data/admins/pageflow/membership.rb +12 -0
  8. data/admins/pageflow/user.rb +5 -3
  9. data/app/assets/javascripts/pageflow/admin/accounts.js +3 -3
  10. data/app/assets/javascripts/pageflow/admin/entries.js +65 -0
  11. data/app/assets/javascripts/pageflow/admin/users.js +1 -1
  12. data/app/assets/javascripts/pageflow/asset_urls.js.erb +1 -0
  13. data/app/assets/javascripts/pageflow/base.js +0 -12
  14. data/app/assets/javascripts/pageflow/components.js +2 -6
  15. data/app/assets/javascripts/pageflow/dist/ui.js +56 -14
  16. data/app/assets/javascripts/pageflow/vendor.js +13 -10
  17. data/app/assets/stylesheets/pageflow/base.scss +0 -7
  18. data/app/assets/stylesheets/pageflow/editor/base.scss +2 -0
  19. data/app/assets/stylesheets/pageflow/editor/composables.scss +5 -1
  20. data/app/assets/stylesheets/pageflow/editor/emulation_mode_button.scss +44 -55
  21. data/app/assets/stylesheets/pageflow/editor/help.scss +2 -2
  22. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/background_image.scss +4 -0
  23. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/watermark.scss +5 -0
  24. data/app/assets/stylesheets/pageflow/ui/tooltip.scss +17 -3
  25. data/app/controllers/pageflow/editor/widgets_controller.rb +1 -1
  26. data/app/helpers/pageflow/admin/entries_helper.rb +16 -0
  27. data/app/helpers/pageflow/pages_helper.rb +1 -0
  28. data/app/helpers/pageflow/structured_data_helper.rb +0 -2
  29. data/app/models/pageflow/account.rb +26 -0
  30. data/app/models/pageflow/draft_entry.rb +13 -3
  31. data/app/models/pageflow/entry.rb +16 -2
  32. data/app/models/pageflow/entry_duplicate.rb +1 -0
  33. data/app/models/pageflow/entry_template.rb +69 -0
  34. data/app/models/pageflow/published_entry.rb +13 -3
  35. data/app/models/pageflow/revision.rb +1 -1
  36. data/app/models/pageflow/theming.rb +8 -47
  37. data/app/policies/pageflow/account_policy.rb +10 -0
  38. data/app/policies/pageflow/entry_template_policy.rb +22 -0
  39. data/app/policies/pageflow/theming_policy.rb +0 -4
  40. data/app/views/admin/accounts/_configuration_label.html.erb +5 -0
  41. data/app/views/admin/accounts/_entry_template_details.html.arb +19 -0
  42. data/app/views/admin/accounts/_form.html.erb +5 -31
  43. data/app/views/admin/accounts/_share_providers_label.html.erb +5 -0
  44. data/app/views/admin/accounts/_theming_details.html.arb +0 -12
  45. data/app/views/admin/entries/_attributes_table.html.arb +5 -0
  46. data/app/views/admin/entries/_not_allowed_to_see_entry_types.json.jbuilder +2 -0
  47. data/app/views/admin/entries/entry_types.json.jbuilder +4 -0
  48. data/app/views/admin/entry_templates/_form.html.erb +58 -0
  49. data/app/views/admin/users/_not_allowed_to_see_user_quota.html.erb +3 -0
  50. data/app/views/components/pageflow/admin/entry_templates_tab.rb +48 -0
  51. data/app/views/pageflow/admin/users/_quota_exhausted.html.erb +1 -1
  52. data/app/views/pageflow/themes/_theme.json.jbuilder +1 -0
  53. data/config/initializers/admin_resource_tabs.rb +5 -0
  54. data/config/initializers/help_entries.rb +1 -5
  55. data/config/locales/de.yml +100 -162
  56. data/config/locales/en.yml +91 -150
  57. data/db/migrate/20200122115400_create_pageflow_entry_templates.rb +75 -0
  58. data/db/migrate/20200206134400_convert_legacy_scrolled_content_element_types.rb +48 -0
  59. data/db/migrate/20200515112500_add_constraints_to_entry_templates.rb +21 -0
  60. data/db/migrate/20200807135200_rename_pageflow_entry_template_entry_type_to_entry_type_name.rb +7 -0
  61. data/entry_types/paged/app/assets/javascripts/pageflow_paged/components.js +7 -0
  62. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +1465 -1348
  63. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +9218 -0
  64. data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-client.js +1 -1
  65. data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-server.js +3 -3
  66. data/entry_types/paged/app/assets/javascripts/pageflow_paged/frontend.js +6 -0
  67. data/entry_types/paged/app/assets/javascripts/pageflow_paged/server_rendering.js +9 -0
  68. data/entry_types/paged/app/assets/javascripts/pageflow_paged/vendor.js +8 -0
  69. data/entry_types/paged/app/controllers/pageflow_paged/application_controller.rb +2 -2
  70. data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/page_background_asset_helper.rb +4 -3
  71. data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/react_server_side_rendering_helper.rb +23 -2
  72. data/entry_types/paged/app/views/layouts/pageflow_paged/application.html.erb +2 -2
  73. data/entry_types/paged/app/views/pageflow_paged/editor/entries/_head.html.erb +2 -2
  74. data/entry_types/paged/app/views/pageflow_paged/entries/_entry.html.erb +1 -1
  75. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/page_background_asset/_element.html.erb +0 -0
  76. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/_widget.html.erb +0 -0
  77. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/page.html.erb +0 -0
  78. data/entry_types/paged/config/initializers/features.rb +1 -1
  79. data/entry_types/paged/config/initializers/help_entries.rb +17 -0
  80. data/entry_types/paged/config/locales/new/help.de.yml +162 -0
  81. data/entry_types/paged/config/locales/new/help.en.yml +153 -0
  82. data/entry_types/paged/lib/pageflow_paged/engine.rb +13 -0
  83. data/entry_types/paged/lib/pageflow_paged/plugin.rb +5 -1
  84. data/entry_types/paged/lib/pageflow_paged/react.rb +12 -0
  85. data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/page_type.rb +2 -2
  86. data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/widget_type.rb +2 -2
  87. data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react-server.js +20613 -0
  88. data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react.js +21495 -0
  89. data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react-server.js +24 -0
  90. data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react.js +24 -0
  91. data/entry_types/scrolled/app/assets/javascripts/pageflow_scrolled/legacy.js +0 -0
  92. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +2 -2
  93. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +15 -4
  94. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -2
  95. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +8 -0
  96. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +10 -1
  97. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +4 -1
  98. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +35 -0
  99. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +33 -0
  100. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +8 -0
  101. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +38 -0
  102. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/content_elements/batch.json.jbuilder +2 -0
  103. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -7
  104. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_seed.json.jbuilder +1 -1
  105. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +32 -4
  106. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +13 -1
  107. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +7 -0
  108. data/entry_types/scrolled/config/initializers/help_entries.rb +16 -0
  109. data/entry_types/scrolled/config/locales/new/de.yml +565 -10
  110. data/entry_types/scrolled/config/locales/new/en.yml +472 -11
  111. data/entry_types/scrolled/config/routes.rb +1 -0
  112. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +31 -0
  113. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDesktop.svg +56 -0
  114. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoMobile.svg +22 -0
  115. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +4 -0
  116. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +3 -1
  117. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +93 -28
  118. data/entry_types/scrolled/lib/tasks/pageflow_scrolled_tasks.rake +133 -0
  119. data/entry_types/scrolled/package/contentElements-editor.js +469 -0
  120. data/entry_types/scrolled/package/contentElements-frontend.css +1 -0
  121. data/entry_types/scrolled/package/contentElements-frontend.js +878 -0
  122. data/entry_types/scrolled/package/editor.js +2725 -2590
  123. data/entry_types/scrolled/package/frontend-server.js +228 -0
  124. data/entry_types/scrolled/package/frontend/EditableText-4264c349.js +1993 -0
  125. data/entry_types/scrolled/package/frontend/Wavesurfer-c3c45324.js +378 -0
  126. data/entry_types/scrolled/package/frontend/components-cfe6a479.js +2115 -0
  127. data/entry_types/scrolled/package/frontend/getPrototypeOf-63c7c8e8.js +86 -0
  128. data/entry_types/scrolled/package/frontend/index.css +9 -0
  129. data/entry_types/scrolled/package/frontend/index.js +4425 -0
  130. data/entry_types/scrolled/package/package.json +28 -7
  131. data/entry_types/scrolled/spec/fixtures/audio.m4a +0 -0
  132. data/entry_types/scrolled/spec/fixtures/video.mp4 +0 -0
  133. data/lib/generators/pageflow/initializer/templates/pageflow.rb +20 -9
  134. data/lib/pageflow/ability_mixin.rb +15 -2
  135. data/lib/pageflow/configuration.rb +6 -5
  136. data/lib/pageflow/engine.rb +1 -0
  137. data/lib/pageflow/entry_type_configuration.rb +1 -0
  138. data/lib/pageflow/global_config_api.rb +5 -4
  139. data/lib/pageflow/react.rb +4 -2
  140. data/lib/pageflow/seeds.rb +0 -2
  141. data/lib/pageflow/theme.rb +4 -0
  142. data/lib/pageflow/themes.rb +5 -1
  143. data/lib/pageflow/version.rb +1 -1
  144. data/{packages/pageflow → package}/config/jest/index.js +2 -2
  145. data/{packages/pageflow → package}/config/jest/transformers/jst.js +1 -1
  146. data/{packages/pageflow → package}/config/jest/transformers/upwardBabel.js +0 -0
  147. data/package/config/webpack.js +22 -0
  148. data/{packages/pageflow → package}/editor.js +493 -1122
  149. data/package/frontend.js +2525 -0
  150. data/{packages/pageflow → package}/package.json +5 -1
  151. data/package/testHelpers.js +732 -0
  152. data/{packages/pageflow → package}/ui.js +56 -14
  153. data/spec/factories/accounts.rb +9 -1
  154. data/spec/factories/entry_templates.rb +9 -0
  155. data/spec/factories/published_entries.rb +8 -1
  156. data/spec/factories/themings.rb +0 -1
  157. metadata +74 -27
  158. data/app/assets/javascripts/pageflow/dist/editor.js +0 -11890
  159. data/app/assets/javascripts/pageflow/dist/frontend.js +0 -5798
  160. data/config/initializers/entry_types.rb +0 -4
  161. data/entry_types/scrolled/package/frontend.js +0 -3404
  162. data/packages/pageflow/config/jest/transformers/cssModules.js +0 -1
  163. data/packages/pageflow/config/webpack.js +0 -15
  164. data/packages/pageflow/testHelpers.js +0 -268
@@ -13,6 +13,7 @@
13
13
  "eslint-plugin-import": "^2.18.2",
14
14
  "eslint-plugin-jest": "^23.0.4",
15
15
  "jest": "^24.9.0",
16
+ "jest-css-modules-processor": "^0.0.9",
16
17
  "jest-jquery-matchers": "^2.1.0",
17
18
  "jest-sinon": "^1.0.0",
18
19
  "sinon": "^7.5.0"
@@ -22,6 +23,9 @@
22
23
  "lint": "eslint ."
23
24
  },
24
25
  "dependencies": {
25
- "core-js": "^3.4.1"
26
+ "backbone-events-standalone": "^0.2.7",
27
+ "classlist.js": "^1.1.20150312",
28
+ "core-js": "^3.4.1",
29
+ "i18n-js": "^3.5.1"
26
30
  }
27
31
  }
@@ -0,0 +1,732 @@
1
+ import $ from 'jquery';
2
+ import _ from 'underscore';
3
+ import { Object as Object$1 } from 'pageflow/ui';
4
+ import Backbone from 'backbone';
5
+ import { Entry, Theme, FileTypes, FilesCollection, SubsetCollection, ImageFile, WidgetTypes, EditorApi, VideoFile, TextTrackFile } from 'pageflow/editor';
6
+ import I18n from 'i18n-js';
7
+
8
+ var Base = Object$1.extend({
9
+ initialize: function initialize($el) {
10
+ this.$el = $el;
11
+ }
12
+ });
13
+
14
+ Base.classMethods = function (Constructor) {
15
+ return {
16
+ find: function find(viewOrParentElement) {
17
+ var selector = Constructor.prototype.selector;
18
+ var parentElement = viewOrParentElement.$el || viewOrParentElement;
19
+ var element = parentElement.find(selector);
20
+
21
+ if (element.length > 1) {
22
+ throw new Error('Selector "' + selector + '" matches multiple elements in view. Expected only one');
23
+ }
24
+
25
+ if (element.length === 0) {
26
+ throw new Error('Selector "' + selector + '" did not match any elements in view.');
27
+ }
28
+
29
+ return new Constructor(element);
30
+ },
31
+ findAll: function findAll(viewOrParentElement) {
32
+ var selector = Constructor.prototype.selector;
33
+ var parentElement = viewOrParentElement.$el || viewOrParentElement;
34
+ var elements = parentElement.find(selector);
35
+ return elements.map(function () {
36
+ return new Constructor($(this));
37
+ }).get();
38
+ },
39
+ findBy: function findBy(predicate, options) {
40
+ var predicateString = options.predicateName ? ' filtered by ' + options.predicateName : '';
41
+ var selector = Constructor.prototype.selector;
42
+ var selectorString = 'Selector "' + selector + '"' + predicateString;
43
+ var elements = options.inView.$el.find(selector);
44
+ var element = elements.filter(function () {
45
+ return predicate($(this));
46
+ });
47
+
48
+ if (element.length > 1) {
49
+ throw new Error(selectorString + ' matches multiple elements in view. Expected only one');
50
+ }
51
+
52
+ if (element.length === 0) {
53
+ throw new Error(selectorString + ' did not match any elements in view.');
54
+ }
55
+
56
+ return new Constructor(element);
57
+ },
58
+ render: function render(view, options) {
59
+ view.render();
60
+
61
+ if (options && options.appendTo) {
62
+ options.appendTo.append(view.$el);
63
+ }
64
+
65
+ return new Constructor(view.$el);
66
+ }
67
+ };
68
+ };
69
+
70
+ Base.extend = function ()
71
+ /* arguments */
72
+ {
73
+ var result = Object$1.extend.apply(this, arguments);
74
+
75
+ _.extend(result, Base.classMethods(result));
76
+
77
+ return result;
78
+ };
79
+
80
+ var DropDownButton = Base.extend({
81
+ selector: '.drop_down_button',
82
+ menuItemNames: function menuItemNames() {
83
+ return this.$el.find('li').map(function () {
84
+ return $(this).data('name');
85
+ }).get();
86
+ },
87
+ menuItemLabels: function menuItemLabels() {
88
+ return this.$el.find('li a').map(function () {
89
+ return $(this).text();
90
+ }).get();
91
+ },
92
+ selectMenuItemByName: function selectMenuItemByName(name) {
93
+ var menuItem = this.$el.find('li').filter(function () {
94
+ return $(this).data('name') == name;
95
+ });
96
+
97
+ if (!menuItem.length) {
98
+ throw new Error('Could not find menu item with name "' + name + '"');
99
+ }
100
+
101
+ menuItem.find('a').trigger('click');
102
+ },
103
+ selectMenuItemByLabel: function selectMenuItemByLabel(label) {
104
+ var menuItemLink = this.$el.find('li a').filter(function () {
105
+ return $(this).text() == label;
106
+ });
107
+
108
+ if (!menuItemLink.length) {
109
+ throw new Error('Could not find menu item with label "' + label + '"');
110
+ }
111
+
112
+ menuItemLink.trigger('click');
113
+ }
114
+ });
115
+
116
+ var FileMetaDataTable = Base.extend({
117
+ selector: '.file_meta_data table',
118
+ values: function values() {
119
+ return this.$el.find('.value').map(function () {
120
+ return $(this).text();
121
+ }).get();
122
+ }
123
+ });
124
+
125
+ var FileStageItem = Base.extend({
126
+ selector: '.file_stage_item'
127
+ });
128
+
129
+ var FileThumbnail = Base.extend({
130
+ selector: '.file_thumbnail',
131
+ backgroundImage: function backgroundImage() {
132
+ return this.$el.css('backgroundImage');
133
+ }
134
+ });
135
+
136
+ var ReferenceInput = Base.extend({
137
+ clickChooseButton: function clickChooseButton() {
138
+ this.$el.find('.choose').trigger('click');
139
+ }
140
+ });
141
+
142
+ var StaticThumbnail = Base.extend({
143
+ selector: '.static_thumbnail',
144
+ backgroundImage: function backgroundImage() {
145
+ return this.$el.css('backgroundImage');
146
+ }
147
+ });
148
+
149
+ var ThemeItem = Base.extend({
150
+ selector: '.theme_item',
151
+ hover: function hover() {
152
+ this.$el.trigger('mouseenter');
153
+ },
154
+ click: function click() {
155
+ this.$el.trigger('click');
156
+ },
157
+ clickUseButton: function clickUseButton() {
158
+ this.$el.find('.use_theme').trigger('click');
159
+ }
160
+ });
161
+
162
+ ThemeItem.findByName = function (themeName, options) {
163
+ return this.findBy(function ($el) {
164
+ return $el.data('themeName') === themeName;
165
+ }, _.extend({
166
+ predicateName: 'theme name ' + themeName
167
+ }, options));
168
+ };
169
+
170
+ var ConfigurationEditorTab = Base.extend({
171
+ selector: '.configuration_editor_tab',
172
+ inputPropertyNames: function inputPropertyNames() {
173
+ return this.$el.find('.input').map(function () {
174
+ return $(this).data('inputPropertyName');
175
+ }).get();
176
+ },
177
+ inputLabels: function inputLabels() {
178
+ return this.$el.find('.input').map(function () {
179
+ return $(this).data('labelText');
180
+ }).get();
181
+ },
182
+ inlineHelpTexts: function inlineHelpTexts() {
183
+ return this.$el.find('.input').map(function () {
184
+ return $(this).data('inlineHelpText');
185
+ }).get();
186
+ }
187
+ });
188
+
189
+ var Tabs = Base.extend({
190
+ selector: '.tabs_view',
191
+ tabNames: function tabNames() {
192
+ return this.$el.find('[data-tab-name]').map(function () {
193
+ return $(this).data('tabName');
194
+ }).get();
195
+ },
196
+ tabLabels: function tabLabels() {
197
+ return this.$el.find('[data-tab-name]').map(function () {
198
+ return $(this).text();
199
+ }).get();
200
+ }
201
+ });
202
+
203
+ var ConfigurationEditor = Base.extend({
204
+ selector: '.configuration_editor',
205
+ tabNames: function tabNames() {
206
+ return Tabs.find(this.$el).tabNames();
207
+ },
208
+ tabLabels: function tabLabels() {
209
+ return Tabs.find(this.$el).tabLabels();
210
+ },
211
+ inputPropertyNames: function inputPropertyNames() {
212
+ return ConfigurationEditorTab.find(this.$el).inputPropertyNames();
213
+ },
214
+ inputLabels: function inputLabels() {
215
+ return ConfigurationEditorTab.find(this.$el).inputLabels();
216
+ },
217
+ inlineHelpTexts: function inlineHelpTexts() {
218
+ return ConfigurationEditorTab.find(this.$el).inlineHelpTexts();
219
+ }
220
+ });
221
+
222
+ var Table = Base.extend({
223
+ selector: '.table_view',
224
+ columnNames: function columnNames() {
225
+ return this.$el.find('th').map(function () {
226
+ return $(this).data('columnName');
227
+ }).get();
228
+ }
229
+ });
230
+
231
+ var ColorInput = Base.extend({
232
+ value: function value() {
233
+ return this._input().val();
234
+ },
235
+ fillIn: function fillIn(value, clock) {
236
+ this._input().val(value);
237
+
238
+ this._input().trigger('keyup');
239
+
240
+ clock.tick(500);
241
+ },
242
+ swatches: function swatches() {
243
+ return this.$el.find('.minicolors-swatches span').map(function () {
244
+ return window.getComputedStyle(this)['background-color'];
245
+ }).get();
246
+ },
247
+ _input: function _input() {
248
+ return this.$el.find('input');
249
+ }
250
+ });
251
+
252
+ function _defineProperty(obj, key, value) {
253
+ if (key in obj) {
254
+ Object.defineProperty(obj, key, {
255
+ value: value,
256
+ enumerable: true,
257
+ configurable: true,
258
+ writable: true
259
+ });
260
+ } else {
261
+ obj[key] = value;
262
+ }
263
+
264
+ return obj;
265
+ }
266
+
267
+ function ownKeys(object, enumerableOnly) {
268
+ var keys = Object.keys(object);
269
+
270
+ if (Object.getOwnPropertySymbols) {
271
+ var symbols = Object.getOwnPropertySymbols(object);
272
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
273
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
274
+ });
275
+ keys.push.apply(keys, symbols);
276
+ }
277
+
278
+ return keys;
279
+ }
280
+
281
+ function _objectSpread2(target) {
282
+ for (var i = 1; i < arguments.length; i++) {
283
+ var source = arguments[i] != null ? arguments[i] : {};
284
+
285
+ if (i % 2) {
286
+ ownKeys(Object(source), true).forEach(function (key) {
287
+ _defineProperty(target, key, source[key]);
288
+ });
289
+ } else if (Object.getOwnPropertyDescriptors) {
290
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
291
+ } else {
292
+ ownKeys(Object(source)).forEach(function (key) {
293
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
294
+ });
295
+ }
296
+ }
297
+
298
+ return target;
299
+ }
300
+
301
+ var Base$1 = Base.extend({
302
+ selector: '.input'
303
+ });
304
+
305
+ Base$1.findByPropertyName = function (propertyName, options) {
306
+ return this.findBy(function (el) {
307
+ return el.data('inputPropertyName') === propertyName;
308
+ }, _objectSpread2({
309
+ predicateName: "input property name '".concat(propertyName, "'")
310
+ }, options));
311
+ };
312
+
313
+ var RadioButtonGroupInput = Base$1.extend({
314
+ values: function values() {
315
+ return this.$el.find('input').map(function () {
316
+ return $(this).attr('value');
317
+ }).get();
318
+ },
319
+ enabledValues: function enabledValues() {
320
+ return this.$el.find('input:not([disabled])').map(function () {
321
+ return $(this).attr('value');
322
+ }).get();
323
+ }
324
+ });
325
+
326
+ var SelectInput = Base$1.extend({
327
+ value: function value() {
328
+ return this.$el.find('select').val();
329
+ },
330
+ values: function values() {
331
+ return this.$el.find('option').map(function () {
332
+ return $(this).attr('value');
333
+ }).get();
334
+ },
335
+ enabledValues: function enabledValues() {
336
+ return this.$el.find('option:not([disabled])').map(function () {
337
+ return $(this).attr('value');
338
+ }).get();
339
+ }
340
+ });
341
+
342
+ /**
343
+ * Build editor Backbone models for tests.
344
+ */
345
+
346
+ var factories = {
347
+ /**
348
+ * Build an entry model.
349
+ *
350
+ * @param {Function} model - Entry type specific entry model
351
+ * @param {Object} [attributes] - Model attributes
352
+ * @param {Object} [options]
353
+ * @param {Object} [options.entryTypeSeed] - Seed data passed to `Entry#setupFromEntryTypeSeed`.
354
+ * @param {FileTypes} [options.fileTypes] - Use {@link #factoriesfiletypes factories.fileTypes} to construct this object.
355
+ * @param {Object} [options.filesAttributes] - An object mapping (underscored) file collection names to arrays of file attributes.
356
+ * @returns {Entry} - An entry Backbone model.
357
+ *
358
+ * @example
359
+ *
360
+ * import {factories} from 'pageflow/testHelpers';
361
+ * import {PagedEntry} from 'editor/models/PagedEntry';
362
+ *
363
+ * const entry = factories.entry(PagedEntry, {slug: 'some-entry'}, {
364
+ * entryTypeSeed: {some: 'data'},
365
+ * fileTypes: factories.fileTypes(f => f.withImageFileType()),
366
+ * filesAttributes: {
367
+ * image_files: [{id: 100, perma_id: 1, basename: 'image'}]
368
+ * }
369
+ * });
370
+ */
371
+ entry: function entry(model, attributes) {
372
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
373
+
374
+ if (typeof model !== 'function') {
375
+ return factories.entry(Entry, model, attributes);
376
+ }
377
+
378
+ ensureFileTypes(options);
379
+ ensureFilesCollections(options);
380
+ var entry = new model(_objectSpread2({
381
+ id: 1
382
+ }, attributes), _.extend({
383
+ storylines: new Backbone.Collection(),
384
+ chapters: new Backbone.Collection()
385
+ }, options));
386
+
387
+ if (entry.setupFromEntryTypeSeed && options.entryTypeSeed) {
388
+ entry.setupFromEntryTypeSeed(options.entryTypeSeed);
389
+ }
390
+
391
+ return entry;
392
+ },
393
+ theme: function theme(attributes, options) {
394
+ return new Theme(attributes, options);
395
+ },
396
+
397
+ /**
398
+ * Construct a file type registry that can be passed to {@link
399
+ * #factoriesentry factories.entry}.
400
+ *
401
+ * The passed function receives a builder object with the following
402
+ * methods that register a corresponding file type:
403
+ *
404
+ * - `withImageFileType([options])`: Registers a file type with collection name `image_files`.
405
+ * - `withVideoFileType([options])`: Registers a file type with collection name `video_files`.
406
+ * - `withTextTrackFileType([options])`: Registers a file type with collection name `text_track_files`.
407
+ *
408
+ * @param {Function} fn - Build function.
409
+ * @returns {FileTypes} - A file Type registry
410
+ */
411
+ fileTypes: function fileTypes(fn) {
412
+ var fileTypes = new FileTypes();
413
+ var fileTypesSetupArray = [];
414
+ var builder = {
415
+ withImageFileType: function withImageFileType(options) {
416
+ fileTypes.register('image_files', _.extend({
417
+ model: ImageFile,
418
+ matchUpload: /^image/,
419
+ topLevelType: true
420
+ }, options));
421
+ fileTypesSetupArray.push({
422
+ collectionName: 'image_files',
423
+ typeName: 'Pageflow::ImageFile',
424
+ i18nKey: 'pageflow/image_files'
425
+ });
426
+ return this;
427
+ },
428
+ withVideoFileType: function withVideoFileType(options) {
429
+ fileTypes.register('video_files', _.extend({
430
+ model: VideoFile,
431
+ matchUpload: /^video/,
432
+ topLevelType: true
433
+ }, options));
434
+ fileTypesSetupArray.push({
435
+ collectionName: 'video_files',
436
+ typeName: 'Pageflow::VideoFile',
437
+ i18nKey: 'pageflow/video_files',
438
+ nestedFileTypes: [{
439
+ collectionName: 'text_track_files'
440
+ }]
441
+ });
442
+ return this;
443
+ },
444
+ withTextTrackFileType: function withTextTrackFileType(options) {
445
+ fileTypes.register('text_track_files', _.extend({
446
+ model: TextTrackFile,
447
+ matchUpload: /vtt$/
448
+ }, options));
449
+ fileTypesSetupArray.push({
450
+ collectionName: 'text_track_files',
451
+ typeName: 'Pageflow::TextTrackFile',
452
+ i18nKey: 'pageflow/text_track_files'
453
+ });
454
+ return this;
455
+ }
456
+ };
457
+ fn.call(builder, builder);
458
+ fileTypes.setup(fileTypesSetupArray);
459
+ return fileTypes;
460
+ },
461
+
462
+ /**
463
+ * Shorthand for calling {@link #factoriesfiletypes
464
+ * factories.fileTypes} with a builder function that calls
465
+ * `withImageFileType`.
466
+ *
467
+ * @param {Object} options - File type options passed to withImageFileType,
468
+ * @returns {FileTypes} - A file Type registry.
469
+ */
470
+ fileTypesWithImageFileType: function fileTypesWithImageFileType(options) {
471
+ return this.fileTypes(function () {
472
+ this.withImageFileType(options);
473
+ });
474
+ },
475
+ imageFileType: function imageFileType(options) {
476
+ return factories.fileTypesWithImageFileType(options).first();
477
+ },
478
+ fileType: function fileType(options) {
479
+ return factories.imageFileType(options);
480
+ },
481
+ filesCollection: function filesCollection(options) {
482
+ return FilesCollection.createForFileType(options.fileType, [{}, {}]);
483
+ },
484
+ nestedFilesCollection: function nestedFilesCollection(options) {
485
+ return new SubsetCollection({
486
+ parentModel: factories.file({
487
+ file_name: options.parentFileName
488
+ }),
489
+ filter: function filter() {
490
+ return true;
491
+ },
492
+ parent: factories.filesCollection({
493
+ fileType: options.fileType
494
+ })
495
+ });
496
+ },
497
+ videoFileWithTextTrackFiles: function videoFileWithTextTrackFiles(options) {
498
+ var fileTypes = this.fileTypes(function () {
499
+ this.withVideoFileType(options.videoFileTypeOptions);
500
+ this.withTextTrackFileType(options.textTrackFileTypeOptions);
501
+ });
502
+ var fileAttributes = {
503
+ video_files: [_.extend({
504
+ id: 1,
505
+ state: 'encoded'
506
+ }, options.videoFileAttributes)],
507
+ text_track_files: _.map(options.textTrackFilesAttributes, function (attributes) {
508
+ return _.extend({
509
+ parent_file_id: 1,
510
+ parent_file_model_type: 'Pageflow::VideoFile'
511
+ }, attributes);
512
+ })
513
+ };
514
+ var entry = factories.entry({}, {
515
+ files: FilesCollection.createForFileTypes(fileTypes, fileAttributes || {}),
516
+ fileTypes: fileTypes
517
+ });
518
+ var videoFiles = entry.getFileCollection(fileTypes.findByCollectionName('video_files'));
519
+ var textTrackFiles = entry.getFileCollection(fileTypes.findByCollectionName('text_track_files'));
520
+ return {
521
+ entry: entry,
522
+ videoFile: videoFiles.first(),
523
+ videoFiles: videoFiles,
524
+ textTrackFiles: textTrackFiles
525
+ };
526
+ },
527
+ imageFilesFixture: function imageFilesFixture(options) {
528
+ var fileTypes = this.fileTypes(function () {
529
+ this.withImageFileType(options.fileTypeOptions);
530
+ });
531
+ var fileAttributes = {
532
+ image_files: [_.extend({
533
+ id: 1,
534
+ state: 'processed'
535
+ }, options.imageFileAttributes)]
536
+ };
537
+ var entry = factories.entry({}, {
538
+ files: FilesCollection.createForFileTypes(fileTypes, fileAttributes || {}),
539
+ fileTypes: fileTypes
540
+ });
541
+ var imageFiles = entry.getFileCollection(fileTypes.findByCollectionName('image_files'));
542
+ return {
543
+ entry: entry,
544
+ imageFile: imageFiles.first(),
545
+ imageFiles: imageFiles
546
+ };
547
+ },
548
+ imageFile: function imageFile(attributes, options) {
549
+ return new ImageFile(attributes, _.extend({
550
+ fileType: this.imageFileType()
551
+ }, options));
552
+ },
553
+ file: function file(attributes, options) {
554
+ return this.imageFile(attributes, options);
555
+ },
556
+ widgetTypes: function widgetTypes(attributesList, beforeSetup) {
557
+ var widgetTypes = new WidgetTypes();
558
+ var attributesListsByRole = {};
559
+
560
+ _(attributesList).each(function (attributes) {
561
+ attributesListsByRole[attributes.role] = attributesListsByRole[attributes.role] || [];
562
+ attributesListsByRole[attributes.role].push(_.extend({
563
+ translationKey: 'widget_name.' + attributes.name
564
+ }, attributes));
565
+ });
566
+
567
+ if (beforeSetup) {
568
+ beforeSetup(widgetTypes);
569
+ }
570
+
571
+ widgetTypes.setup(attributesListsByRole);
572
+ return widgetTypes;
573
+ },
574
+ editorApi: function editorApi(beforeSetup) {
575
+ var api = new EditorApi({
576
+ router: {
577
+ navigate: function navigate(path, _ref) {
578
+ var trigger = _ref.trigger;
579
+
580
+ if (trigger) {
581
+ api.trigger('navigate', path);
582
+ }
583
+ }
584
+ }
585
+ });
586
+
587
+ if (beforeSetup) {
588
+ beforeSetup(api);
589
+ }
590
+
591
+ api.pageTypes.setup(_.map(api.pageTypes.clientSideConfigs, function (config, name) {
592
+ return {
593
+ name: name,
594
+ translation_key_prefix: 'pageflow.' + name,
595
+ translation_key: 'pageflow.' + name + '.name',
596
+ category_translation_key: 'pageflow.' + name + '.category',
597
+ description_translation_key: 'pageflow.' + name + '.description'
598
+ };
599
+ }));
600
+ return api;
601
+ }
602
+ };
603
+
604
+ function ensureFileTypes(options) {
605
+ if (!options.fileTypes) {
606
+ options.fileTypes = new FileTypes();
607
+ options.fileTypes.setup([]);
608
+ }
609
+ }
610
+
611
+ function ensureFilesCollections(options) {
612
+ if (!options.files) {
613
+ options.files = FilesCollection.createForFileTypes(options.fileTypes, options.filesAttributes);
614
+ }
615
+ }
616
+
617
+ var state = window.pageflow || {};
618
+
619
+ /**
620
+ * Setup global state for testing Backbone editro components.
621
+ *
622
+ * For some editor components like (some views or models) it's easier
623
+ * to depend on the global mutable state (available via the `$state`
624
+ * module alias) instead of injecting dependencies. This helper can be
625
+ * used to test these components in isolation.
626
+ *
627
+ * @param {Object} mapping -
628
+ * Properties to set on the global state. Functions as values will
629
+ * be evaluated and the return value will be assigned instead.
630
+ */
631
+
632
+ var setupGlobals = function setupGlobals(mapping) {
633
+ var globalsBackup;
634
+ beforeEach(function () {
635
+ if (globalsBackup) {
636
+ throw new Error('There can only be one setupGlobals call per test.');
637
+ }
638
+
639
+ globalsBackup = {};
640
+
641
+ _.each(mapping, function (value, key) {
642
+ globalsBackup[key] = state[key];
643
+ state[key] = typeof value === 'function' ? value.call(this) : value;
644
+ });
645
+ });
646
+ afterEach(function () {
647
+ _.each(mapping, function (_, key) {
648
+ state[key] = globalsBackup[key];
649
+ });
650
+
651
+ globalsBackup = null;
652
+ });
653
+ };
654
+
655
+ /**
656
+ * Define translations to use in tests.
657
+ *
658
+ * @param {Object} translations -
659
+ * A mapping of either the form `(translation key => translated
660
+ * text)`. Translation keys can contains dots.
661
+ * @param {Object} [options]
662
+ * @param {boolean} [options.multiLocale] -
663
+ * Set to `true` if keys include the locale name.
664
+ *
665
+ * @example
666
+ * import {useFakeTranslations} from 'pageflow/testHelpers';
667
+ * import I18n from 'i18n-js';
668
+ *
669
+ * describe('...', () => {
670
+ * useFakeTranslations({
671
+ * 'some.key': 'some translation'
672
+ * });
673
+ *
674
+ * it('...', () => {
675
+ * I18n.t('some.key') // => 'some translation'
676
+ * });
677
+ * });
678
+ *
679
+ * @example
680
+ * import {useFakeTranslations} from 'pageflow/testHelpers';
681
+ * import I18n from 'i18n-js';
682
+ *
683
+ * describe('...', () => {
684
+ * useFakeTranslations({
685
+ * 'en.some.key': 'some text',
686
+ * 'de.some.key': 'etwas Text'
687
+ * }, {multiLocale: true});
688
+ *
689
+ * it('...', () => {
690
+ * I18n.locale = 'de';
691
+ * I18n.t('some.key') // => 'etwas Text'
692
+ * });
693
+ * });
694
+ */
695
+
696
+ function useFakeTranslations(translations) {
697
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
698
+ multiLocale = _ref.multiLocale;
699
+
700
+ var originalTranslations;
701
+ beforeEach(function () {
702
+ originalTranslations = I18n.translations;
703
+
704
+ if (multiLocale) {
705
+ I18n.translations = keysWithDotsToNestedObjects(translations);
706
+ } else {
707
+ I18n.translations = {
708
+ en: keysWithDotsToNestedObjects(translations)
709
+ };
710
+ }
711
+ });
712
+ afterEach(function () {
713
+ I18n.translations = originalTranslations;
714
+ });
715
+ }
716
+
717
+ function keysWithDotsToNestedObjects(translations) {
718
+ return _(translations).reduce(function (result, value, key) {
719
+ var keys = key.split('.');
720
+ var last = keys.pop();
721
+
722
+ var inner = _(keys).reduce(function (r, key) {
723
+ r[key] = r[key] || {};
724
+ return r[key];
725
+ }, result);
726
+
727
+ inner[last] = value;
728
+ return result;
729
+ }, {});
730
+ }
731
+
732
+ export { ColorInput, ConfigurationEditor, ConfigurationEditorTab, DropDownButton, FileMetaDataTable, FileStageItem, FileThumbnail, RadioButtonGroupInput, ReferenceInput, SelectInput, StaticThumbnail, Table, Tabs, ThemeItem, factories, setupGlobals, useFakeTranslations };