pageflow 15.1.2 → 15.2.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -185
  3. data/README.md +1 -2
  4. data/admins/pageflow/accounts.rb +94 -19
  5. data/app/assets/javascripts/pageflow/admin/accounts.js +2 -2
  6. data/app/assets/javascripts/pageflow/dist/frontend.js +2 -0
  7. data/app/assets/javascripts/pageflow/dist/ui.js +9 -0
  8. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/background_image.scss +4 -0
  9. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/watermark.scss +5 -0
  10. data/app/controllers/pageflow/editor/widgets_controller.rb +1 -1
  11. data/app/helpers/pageflow/pages_helper.rb +1 -0
  12. data/app/models/pageflow/account.rb +6 -0
  13. data/app/models/pageflow/entry.rb +8 -1
  14. data/app/models/pageflow/entry_template.rb +55 -0
  15. data/app/models/pageflow/revision.rb +1 -1
  16. data/app/models/pageflow/theming.rb +8 -47
  17. data/app/policies/pageflow/entry_template_policy.rb +18 -0
  18. data/app/policies/pageflow/theming_policy.rb +0 -4
  19. data/app/views/admin/accounts/_configuration_label.html.erb +5 -0
  20. data/app/views/admin/accounts/_entry_template_details.html.arb +17 -0
  21. data/app/views/admin/accounts/_form.html.erb +43 -23
  22. data/app/views/admin/accounts/_share_providers_label.html.erb +5 -0
  23. data/app/views/admin/accounts/_theming_details.html.arb +0 -12
  24. data/app/views/pageflow/themes/_theme.json.jbuilder +1 -0
  25. data/config/locales/de.yml +12 -7
  26. data/config/locales/en.yml +12 -7
  27. data/db/migrate/20200122115400_create_pageflow_entry_templates.rb +75 -0
  28. data/db/migrate/20200206134400_convert_legacy_scrolled_content_element_types.rb +48 -0
  29. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +32 -3
  30. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +1 -0
  31. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +4 -1
  32. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +2 -1
  33. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +35 -0
  34. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_seed.json.jbuilder +1 -1
  35. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +14 -2
  36. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +10 -1
  37. data/entry_types/scrolled/config/locales/new/de.yml +231 -8
  38. data/entry_types/scrolled/config/locales/new/en.yml +228 -10
  39. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +3 -0
  40. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +9 -4
  41. data/entry_types/scrolled/lib/tasks/pageflow_scrolled_tasks.rake +96 -0
  42. data/entry_types/scrolled/package/editor.js +498 -2561
  43. data/entry_types/scrolled/package/frontend.js +713 -1238
  44. data/entry_types/scrolled/package/package.json +12 -2
  45. data/lib/pageflow/ability_mixin.rb +3 -2
  46. data/lib/pageflow/seeds.rb +0 -2
  47. data/lib/pageflow/theme.rb +4 -0
  48. data/lib/pageflow/themes.rb +5 -1
  49. data/lib/pageflow/version.rb +1 -1
  50. data/packages/pageflow/config/jest/index.js +0 -1
  51. data/packages/pageflow/config/jest/transformers/jst.js +1 -1
  52. data/packages/pageflow/config/webpack.js +0 -1
  53. data/packages/pageflow/editor.js +23 -3
  54. data/packages/pageflow/package.json +2 -1
  55. data/packages/pageflow/testHelpers.js +367 -4
  56. data/packages/pageflow/ui.js +9 -0
  57. data/spec/factories/accounts.rb +6 -0
  58. data/spec/factories/entry_templates.rb +8 -0
  59. data/spec/factories/published_entries.rb +3 -1
  60. data/spec/factories/themings.rb +0 -1
  61. metadata +11 -1
@@ -7,14 +7,20 @@
7
7
  "author": "Codevise Solutions GmbH <info@codevise.de>",
8
8
  "license": "MIT",
9
9
  "dependencies": {
10
+ "prop-types": "^15.7.2",
10
11
  "react": "^16.9.0",
11
12
  "react-dom": "^16.9.0",
12
- "react-tooltip": "^3.11.1"
13
+ "react-player": "^1.15.2",
14
+ "react-tooltip": "^3.11.1",
15
+ "react-compare-image": "^2.0.4"
13
16
  },
14
17
  "peerDependencies": {
15
18
  "pageflow": "15.1.0"
16
19
  },
17
20
  "devDependencies": {
21
+ "@percy/storybook": "^3.2.0",
22
+ "@storybook/addon-viewport": "^5.3.13",
23
+ "@storybook/react": "^5.3.9",
18
24
  "@testing-library/jest-dom": "^4.2.4",
19
25
  "@testing-library/react": "^9.4.0",
20
26
  "@testing-library/react-hooks": "^3.2.1",
@@ -22,6 +28,7 @@
22
28
  "@typescript-eslint/parser": "2.x",
23
29
  "babel-eslint": "10.x",
24
30
  "babel-jest": "^24.9.0",
31
+ "babel-loader": "^8.0.6",
25
32
  "eslint": "6.x",
26
33
  "eslint-config-react-app": "^5.1.0",
27
34
  "eslint-import-resolver-jest": "^3.0.0",
@@ -38,6 +45,9 @@
38
45
  },
39
46
  "scripts": {
40
47
  "test": "jest",
41
- "lint": "eslint ."
48
+ "lint": "eslint .",
49
+ "start-storybook": "start-storybook",
50
+ "build-storybook": "build-storybook -o .storybook/out",
51
+ "snapshot": "STORYBOOK_SPLIT=true build-storybook --quiet -o .storybook/out && PERCY_TOKEN=${PERCY_TOKEN:-$PT} percy-storybook --widths=1280 --build_dir=.storybook/out"
42
52
  }
43
53
  }
@@ -214,8 +214,8 @@ module Pageflow
214
214
  ThemingPolicy.new(user, theming).edit?
215
215
  end
216
216
 
217
- can :index_widgets_for, Theming do |theming|
218
- ThemingPolicy.new(user, theming).index_widgets_for?
217
+ can :edit, EntryTemplate do |entry_template|
218
+ EntryTemplatePolicy.new(user, entry_template).edit?
219
219
  end
220
220
 
221
221
  can :create, ::User do |managed_user|
@@ -260,6 +260,7 @@ module Pageflow
260
260
  can :manage, Pageflow.config.file_types.map(&:model)
261
261
  can :manage, Folder
262
262
  can :manage, Theming
263
+ can :manage, EntryTemplate
263
264
  can :manage, ::User
264
265
  end
265
266
  end
@@ -54,8 +54,6 @@ module Pageflow
54
54
  # @return [Theming] newly built theming
55
55
  def build_default_theming_for(account, attributes = {}, &block)
56
56
  default_attributes = {
57
- theme_name: Pageflow.config_for(account).themes.names.first,
58
-
59
57
  imprint_link_label: 'Impressum',
60
58
  imprint_link_url: 'http://example.com/impressum.html',
61
59
  copyright_link_label: '&copy; Pageflow 2014',
@@ -44,6 +44,10 @@ module Pageflow
44
44
  !!@options[:emphasized_pages]
45
45
  end
46
46
 
47
+ def supports_hide_logo_on_pages?
48
+ !!@options[:hide_logo_option]
49
+ end
50
+
47
51
  def page_change_by_scrolling?
48
52
  !@options[:no_page_change_by_scrolling]
49
53
  end
@@ -31,7 +31,11 @@ module Pageflow
31
31
  #
32
32
  # @option options :no_hide_text_on_swipe [Boolean]
33
33
  # Pass true if hiding the text by swiping to left shall be
34
- # deactived on mobile devices.
34
+ # deactivated on mobile devices.
35
+ #
36
+ # @option options :hide_logo_option [Boolean]
37
+ # Pass true if hiding the logo on specific pages should be supported
38
+ # as an option in the editor.
35
39
  def register(name, options = {})
36
40
  @themes[name] = Theme.new(name, options)
37
41
  end
@@ -1,3 +1,3 @@
1
1
  module Pageflow
2
- VERSION = '15.1.2'.freeze
2
+ VERSION = '15.2.0'.freeze
3
3
  end
@@ -10,7 +10,6 @@ module.exports = {
10
10
  '^backbone$': resolve('../../src/vendor/backbone'),
11
11
  '^underscore$': resolve('../../src/vendor/underscore'),
12
12
  '^cocktail$': resolve('../../src/vendor/cocktail'),
13
- '^i18n-js$': resolve('../../src/vendor/i18n'),
14
13
  '^iscroll$': resolve('../../src/vendor/iscroll'),
15
14
  '^wysihtml5': resolve('../../spec/support/wysihtmlStub'),
16
15
  },
@@ -3,6 +3,6 @@ const jst = jstPlugin();
3
3
 
4
4
  module.exports = {
5
5
  process(data, id) {
6
- return jst.transform(data, id).replace('export default', 'var I18n = require("i18n-js").default; module.exports =');
6
+ return jst.transform(data, id).replace('export default', 'var I18n = require("i18n-js"); module.exports =');
7
7
  }
8
8
  };
@@ -8,7 +8,6 @@ module.exports = {
8
8
  'jquery.minicolors': 'jQuery',
9
9
  'underscore': '_',
10
10
  'backbone.marionette': 'Backbone.Marionette',
11
- 'i18n-js': 'I18n',
12
11
  'iscroll': 'IScroll',
13
12
  'wysihtml5': 'wysihtml5'
14
13
  }
@@ -1119,7 +1119,9 @@ var EditorApi = Object$1.extend(
1119
1119
  }
1120
1120
 
1121
1121
  var payloadJson = JSON.parse(decodeURIComponent(encodedPayload));
1122
- return new this.fileSelectionHandlers[handlerName](payloadJson);
1122
+ return new this.fileSelectionHandlers[handlerName](_objectSpread({}, payloadJson, {
1123
+ entry: state.entry
1124
+ }));
1123
1125
  },
1124
1126
  createPageConfigurationEditorView: function createPageConfigurationEditorView(page, options) {
1125
1127
  var view = this.pageTypes.findByPage(page).createConfigurationEditorView(_$1.extend(options, {
@@ -1132,6 +1134,13 @@ var EditorApi = Object$1.extend(
1132
1134
 
1133
1135
  var editor$1 = new EditorApi();
1134
1136
  var startEditor = function startEditor(options) {
1137
+ // In Webpack builds, I18n object from the i18n-js module is not
1138
+ // identical to window.I18n which is provided by the i18n-js gem via
1139
+ // the asset pipeline. Make translations provided via the asset
1140
+ // pipeline available in Webpack bundle.
1141
+ I18n$1.defaultLocale = window.I18n.defaultLocale;
1142
+ I18n$1.locale = window.I18n.locale;
1143
+ I18n$1.translations = window.I18n.translations;
1135
1144
  $(function () {
1136
1145
  $.when($.getJSON('/editor/entries/' + options.entryId + '/seed'), pageflow.browser.detectFeatures()).done(function (result) {
1137
1146
  app.start(result[0]);
@@ -2259,6 +2268,9 @@ var Theme = Backbone.Model.extend({
2259
2268
  },
2260
2269
  supportsScrollIndicatorModes: function supportsScrollIndicatorModes() {
2261
2270
  return this.get('scroll_indicator_modes');
2271
+ },
2272
+ supportsHideLogoOnPages: function supportsHideLogoOnPages() {
2273
+ return this.get('hide_logo_option');
2262
2274
  }
2263
2275
  });
2264
2276
 
@@ -3899,6 +3911,7 @@ var BackButtonDecoratorView = Marionette.Layout.extend({
3899
3911
  this.outlet.show(this.options.view);
3900
3912
  },
3901
3913
  goBack: function goBack() {
3914
+ this.options.view.onGoBack && this.options.view.onGoBack();
3902
3915
  editor$1.navigate('/', {
3903
3916
  trigger: true
3904
3917
  });
@@ -5473,6 +5486,8 @@ var EditPageView = Marionette.Layout.extend({
5473
5486
  'change:template': 'load'
5474
5487
  },
5475
5488
  onRender: function onRender() {
5489
+ var _this = this;
5490
+
5476
5491
  this.pageTypeContainer.show(new ExtendedSelectInputView({
5477
5492
  model: this.model,
5478
5493
  propertyName: 'template',
@@ -5483,7 +5498,8 @@ var EditPageView = Marionette.Layout.extend({
5483
5498
  descriptionTranslationKeyProperty: 'description_translation_key',
5484
5499
  pictogramClass: 'type_pictogram',
5485
5500
  helpLinkClicked: function helpLinkClicked(value) {
5486
- var pageType = this.options.api.pageTypes.findByName(value);
5501
+ var pageType = _this.options.api.pageTypes.findByName(value);
5502
+
5487
5503
  app.trigger('toggle-help', pageType.seed.help_entry_translation_key);
5488
5504
  }
5489
5505
  }));
@@ -8093,7 +8109,7 @@ var ListView = Marionette.ItemView.extend({
8093
8109
  typeName: this.options.itemTypeName,
8094
8110
  typeDescription: this.options.itemTypeDescription,
8095
8111
  isInvalid: this.options.itemIsInvalid
8096
- }, _$1(this.options).pick('onEdit', 'onDelete', 'highlight')),
8112
+ }, _$1(this.options).pick('onEdit', 'onRemove', 'highlight')),
8097
8113
  blankSlateViewConstructor: Marionette.ItemView.extend({
8098
8114
  tagName: 'li',
8099
8115
  className: 'list_blank_slate',
@@ -8478,6 +8494,10 @@ ConfigurationEditorTabView.groups.define('options', function (options) {
8478
8494
  collection: state.audioFiles
8479
8495
  });
8480
8496
 
8497
+ if (theme.supportsHideLogoOnPages()) {
8498
+ this.input('hide_logo', CheckBoxInputView);
8499
+ }
8500
+
8481
8501
  if (options.canPauseAtmo) {
8482
8502
  this.input('atmo_during_playback', SelectInputView, {
8483
8503
  values: pageflow.Atmo.duringPlaybackModes
@@ -22,6 +22,7 @@
22
22
  "lint": "eslint ."
23
23
  },
24
24
  "dependencies": {
25
- "core-js": "^3.4.1"
25
+ "core-js": "^3.4.1",
26
+ "i18n-js": "^3.5.1"
26
27
  }
27
28
  }
@@ -1,7 +1,281 @@
1
- import Backbone from 'backbone';
1
+ import $ from 'jquery';
2
2
  import _ from 'underscore';
3
+ import { Object as Object$1 } from 'pageflow/ui';
4
+ import Backbone from 'backbone';
3
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
+ });
4
251
 
252
+ var SelectInput = Base.extend({
253
+ selector: 'select',
254
+ values: function values() {
255
+ return this.$el.find('option').map(function () {
256
+ return $(this).attr('value');
257
+ }).get();
258
+ }
259
+ });
260
+
261
+ function _defineProperty(obj, key, value) {
262
+ if (key in obj) {
263
+ Object.defineProperty(obj, key, {
264
+ value: value,
265
+ enumerable: true,
266
+ configurable: true,
267
+ writable: true
268
+ });
269
+ } else {
270
+ obj[key] = value;
271
+ }
272
+
273
+ return obj;
274
+ }
275
+
276
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
277
+
278
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
5
279
  /**
6
280
  * Build editor Backbone models for tests.
7
281
  */
@@ -40,7 +314,9 @@ var factories = {
40
314
 
41
315
  ensureFileTypes(options);
42
316
  ensureFilesCollections(options);
43
- var entry = new model(attributes, _.extend({
317
+ var entry = new model(_objectSpread({
318
+ id: 1
319
+ }, attributes), _.extend({
44
320
  storylines: new Backbone.Collection(),
45
321
  chapters: new Backbone.Collection()
46
322
  }, options));
@@ -233,7 +509,17 @@ var factories = {
233
509
  return widgetTypes;
234
510
  },
235
511
  editorApi: function editorApi(beforeSetup) {
236
- var api = new EditorApi();
512
+ var api = new EditorApi({
513
+ router: {
514
+ navigate: function navigate(path, _ref) {
515
+ var trigger = _ref.trigger;
516
+
517
+ if (trigger) {
518
+ api.trigger('navigate', path);
519
+ }
520
+ }
521
+ }
522
+ });
237
523
 
238
524
  if (beforeSetup) {
239
525
  beforeSetup(api);
@@ -265,4 +551,81 @@ function ensureFilesCollections(options) {
265
551
  }
266
552
  }
267
553
 
268
- export { factories };
554
+ /**
555
+ * Define translations to use in tests.
556
+ *
557
+ * @param {Object} translations -
558
+ * A mapping of either the form `(translation key => translated
559
+ * text)`. Translation keys can contains dots.
560
+ * @param {Object} [options]
561
+ * @param {boolean} [options.multiLocale] -
562
+ * Set to `true` if keys include the locale name.
563
+ *
564
+ * @example
565
+ * import {useFakeTranslations} from 'pageflow/testHelpers';
566
+ * import I18n from 'i18n-js';
567
+ *
568
+ * describe('...', () => {
569
+ * useFakeTranslations({
570
+ * 'some.key': 'some translation'
571
+ * });
572
+ *
573
+ * it('...', () => {
574
+ * I18n.t('some.key') // => 'some translation'
575
+ * });
576
+ * });
577
+ *
578
+ * @example
579
+ * import {useFakeTranslations} from 'pageflow/testHelpers';
580
+ * import I18n from 'i18n-js';
581
+ *
582
+ * describe('...', () => {
583
+ * useFakeTranslations({
584
+ * 'en.some.key': 'some text',
585
+ * 'de.some.key': 'etwas Text'
586
+ * }, {multiLocale: true});
587
+ *
588
+ * it('...', () => {
589
+ * I18n.locale = 'de';
590
+ * I18n.t('some.key') // => 'etwas Text'
591
+ * });
592
+ * });
593
+ */
594
+
595
+ function useFakeTranslations(translations) {
596
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
597
+ multiLocale = _ref.multiLocale;
598
+
599
+ var originalTranslations;
600
+ beforeEach(function () {
601
+ originalTranslations = I18n.translations;
602
+
603
+ if (multiLocale) {
604
+ I18n.translations = keysWithDotsToNestedObjects(translations);
605
+ } else {
606
+ I18n.translations = {
607
+ en: keysWithDotsToNestedObjects(translations)
608
+ };
609
+ }
610
+ });
611
+ afterEach(function () {
612
+ I18n.translations = originalTranslations;
613
+ });
614
+ }
615
+
616
+ function keysWithDotsToNestedObjects(translations) {
617
+ return _(translations).reduce(function (result, value, key) {
618
+ var keys = key.split('.');
619
+ var last = keys.pop();
620
+
621
+ var inner = _(keys).reduce(function (r, key) {
622
+ r[key] = r[key] || {};
623
+ return r[key];
624
+ }, result);
625
+
626
+ inner[last] = value;
627
+ return result;
628
+ }, {});
629
+ }
630
+
631
+ export { ColorInput, ConfigurationEditor, ConfigurationEditorTab, DropDownButton, FileMetaDataTable, FileStageItem, FileThumbnail, ReferenceInput, SelectInput, StaticThumbnail, Table, Tabs, ThemeItem, factories, useFakeTranslations };