pageflow 15.1.0 → 15.2.2

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -161
  3. data/README.md +1 -2
  4. data/admins/pageflow/accounts.rb +94 -19
  5. data/app/assets/javascripts/pageflow/admin/accounts.js +3 -3
  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/draft_entry.rb +13 -3
  14. data/app/models/pageflow/entry.rb +8 -1
  15. data/app/models/pageflow/entry_template.rb +55 -0
  16. data/app/models/pageflow/published_entry.rb +13 -3
  17. data/app/models/pageflow/revision.rb +1 -1
  18. data/app/models/pageflow/theming.rb +8 -47
  19. data/app/policies/pageflow/entry_template_policy.rb +18 -0
  20. data/app/policies/pageflow/theming_policy.rb +0 -4
  21. data/app/views/admin/accounts/_configuration_label.html.erb +5 -0
  22. data/app/views/admin/accounts/_entry_template_details.html.arb +17 -0
  23. data/app/views/admin/accounts/_form.html.erb +43 -23
  24. data/app/views/admin/accounts/_share_providers_label.html.erb +5 -0
  25. data/app/views/admin/accounts/_theming_details.html.arb +0 -12
  26. data/app/views/pageflow/themes/_theme.json.jbuilder +1 -0
  27. data/config/locales/de.yml +12 -7
  28. data/config/locales/en.yml +12 -7
  29. data/db/migrate/20200122115400_create_pageflow_entry_templates.rb +75 -0
  30. data/db/migrate/20200206134400_convert_legacy_scrolled_content_element_types.rb +48 -0
  31. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +42 -4
  32. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +1 -0
  33. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +4 -1
  34. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +2 -1
  35. data/entry_types/scrolled/app/helpers/pageflow_scrolled/i18n_helper.rb +35 -0
  36. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_seed.json.jbuilder +1 -1
  37. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +14 -2
  38. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +10 -1
  39. data/entry_types/scrolled/config/locales/new/de.yml +231 -8
  40. data/entry_types/scrolled/config/locales/new/en.yml +228 -10
  41. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +3 -0
  42. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +9 -4
  43. data/entry_types/scrolled/lib/tasks/pageflow_scrolled_tasks.rake +96 -0
  44. data/entry_types/scrolled/package/contentElements-editor.js +410 -0
  45. data/entry_types/scrolled/package/contentElements-frontend.js +533 -0
  46. data/entry_types/scrolled/package/editor.js +498 -2561
  47. data/entry_types/scrolled/package/frontend.js +713 -1238
  48. data/entry_types/scrolled/package/package.json +12 -2
  49. data/lib/pageflow/ability_mixin.rb +3 -2
  50. data/lib/pageflow/seeds.rb +0 -2
  51. data/lib/pageflow/theme.rb +4 -0
  52. data/lib/pageflow/themes.rb +5 -1
  53. data/lib/pageflow/version.rb +1 -1
  54. data/packages/pageflow/config/jest/index.js +0 -1
  55. data/packages/pageflow/config/jest/transformers/jst.js +1 -1
  56. data/packages/pageflow/config/webpack.js +0 -1
  57. data/packages/pageflow/editor.js +33 -4
  58. data/packages/pageflow/package.json +2 -1
  59. data/packages/pageflow/testHelpers.js +367 -4
  60. data/packages/pageflow/ui.js +9 -0
  61. data/spec/factories/accounts.rb +6 -0
  62. data/spec/factories/entry_templates.rb +8 -0
  63. data/spec/factories/published_entries.rb +3 -1
  64. data/spec/factories/themings.rb +0 -1
  65. metadata +14 -4
  66. data/app/assets/javascripts/pageflow/dist/editor.js +0 -11881
  67. data/app/assets/javascripts/pageflow/dist/index.js +0 -3
@@ -21,12 +21,15 @@ module PageflowScrolled
21
21
  def editor_pack
22
22
  create_file 'app/javascript/packs/pageflow-scrolled-editor.js', <<-JS
23
23
  import 'pageflow-scrolled/editor';
24
+ import 'pageflow-scrolled/contentElements-editor';
25
+ import 'pageflow-scrolled/contentElements-frontend';
24
26
  JS
25
27
  end
26
28
 
27
29
  def frontend_pack
28
30
  create_file 'app/javascript/packs/pageflow-scrolled-frontend.js', <<-JS
29
31
  import 'pageflow-scrolled/frontend';
32
+ import 'pageflow-scrolled/contentElements-frontend';
30
33
  JS
31
34
  end
32
35
  end
@@ -102,8 +102,14 @@ module PageflowScrolled
102
102
  end
103
103
 
104
104
  def create_content_element(section, content_element_config, position, image_files_by_name)
105
- if %w[stickyImage inlineImage].include?(content_element_config['type'])
106
- rewrite_file_references!(content_element_config['props'], ['id'], image_files_by_name)
105
+ if %w[stickyImage inlineImage inlineBeforeAfter].include?(
106
+ content_element_config['type']
107
+ )
108
+ rewrite_file_references!(
109
+ content_element_config['props'],
110
+ ['id', 'before_id', 'after_id'],
111
+ image_files_by_name
112
+ )
107
113
  end
108
114
 
109
115
  section.content_elements.create!(
@@ -126,8 +132,7 @@ module PageflowScrolled
126
132
 
127
133
  def non_image_reference?(value)
128
134
  value.starts_with?('#') ||
129
- value.starts_with?('video') ||
130
- value.starts_with?('beforeAfter')
135
+ value.starts_with?('video')
131
136
  end
132
137
  end
133
138
  end
@@ -0,0 +1,96 @@
1
+ namespace :pageflow_scrolled do
2
+ desc 'Generate dummy app for current Rails version.'
3
+ task :dummy do
4
+ require 'pageflow/support'
5
+ Pageflow::Dummy.setup
6
+ end
7
+
8
+ namespace :storybook do
9
+ namespace :seed do
10
+ task :setup, [:output] => [:destroy_entry, :create_entry, :generate_json]
11
+
12
+ desc 'Destroy entry to generate Storybook entry JSON seed from'
13
+ task destroy_entry: :environment do
14
+ entry = Pageflow::Entry.find_by_title('Storybook seed')
15
+
16
+ if entry
17
+ puts "Destroying entry 'Storybook seed'"
18
+ entry.destroy
19
+ end
20
+ end
21
+
22
+ desc 'Create entry to generate Storybook entry JSON seed from'
23
+ task create_entry: :environment do
24
+ seeds = Module.new do
25
+ extend Pageflow::Seeds
26
+ extend PageflowScrolled::Seeds
27
+ end
28
+
29
+ if ENV['PAGEFLOW_PAPERCLIP_S3_ROOT']
30
+ Pageflow.config.paperclip_s3_root = ENV['PAGEFLOW_PAPERCLIP_S3_ROOT']
31
+ end
32
+
33
+ if ENV['PAGEFLOW_SCROLLED_DB_SEED_SKIP_FILES'] == 'true'
34
+ puts 'Skipping file uploads to S3.'
35
+ Paperclip::Storage::S3.class_eval { def flush_writes; end }
36
+ end
37
+
38
+ account = seeds.account(name: 'Storybook seed')
39
+ seeds.sample_scrolled_entry(title: 'Storybook seed',
40
+ account: account,
41
+ chapters: [],
42
+ image_files: {
43
+ turtle: {
44
+ url: 'https://s3-eu-west-1.amazonaws.com/de.codevise.pageflow.development/pageflow-next/seed-assets/images/04_turtle.jpg',
45
+ configuration: {
46
+ focusX: 24,
47
+ focusY: 40,
48
+ testReferenceName: 'turtle'
49
+ }
50
+ }.stringify_keys,
51
+ churchAfter: {
52
+ url: 'https://s3-eu-west-1.amazonaws.com/de.codevise.pageflow.development/pageflow-next/seed-assets/images/17_haldern_church_after.jpg',
53
+ configuration: {
54
+ testReferenceName: 'churchAfter'
55
+ }
56
+ }.stringify_keys,
57
+ churchBefore: {
58
+ url: 'https://s3-eu-west-1.amazonaws.com/de.codevise.pageflow.development/pageflow-next/seed-assets/images/16_haldern_church_before.jpg',
59
+ configuration: {
60
+ testReferenceName: 'churchBefore'
61
+ }
62
+ }.stringify_keys
63
+ })
64
+ end
65
+
66
+ desc 'Generate Storybook entry JSON seed'
67
+ task :generate_json, [:output] => :environment do |_t, args|
68
+ entry = Pageflow::Entry.find_by_title('Storybook seed')
69
+
70
+ unless entry
71
+ puts 'Seed entry does not exist. Run pageflow_scrolled:storybook:seed:create_entry first.'
72
+ exit 1
73
+ end
74
+
75
+ draft_entry = Pageflow::DraftEntry.new(entry)
76
+
77
+ seed =
78
+ I18n.with_locale(draft_entry.locale) do
79
+ PageflowScrolled::EntriesController
80
+ .render(inline: 'scrolled_entry_json_seed(json, entry)',
81
+ type: :jbuilder,
82
+ locals: {entry: draft_entry})
83
+ end
84
+
85
+ if args[:output].blank?
86
+ puts 'Missing argument: Pass output path via '\
87
+ '`rake pageflow_scrolled:storybook:seed:setup[some/path/seed.json]`'
88
+ exit 1
89
+ end
90
+
91
+ File.write(args[:output], seed)
92
+ puts "Wrote #{args[:output]}"
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,410 @@
1
+ import { editor as editor$1 } from 'pageflow-scrolled/editor';
2
+ import { TextInputView, TextAreaInputView, SliderInputView, CheckBoxInputView, UrlInputView, SelectInputView, cssModulesUtils, ConfigurationEditorView } from 'pageflow/ui';
3
+ import { FileInputView, ColorInputView, ListView, transientReferences } from 'pageflow/editor';
4
+ import Marionette from 'backbone.marionette';
5
+ import _ from 'underscore';
6
+ import Backbone from 'backbone';
7
+ import I18n$1 from 'i18n-js';
8
+
9
+ editor$1.contentElementTypes.register('heading', {
10
+ configurationEditor: function configurationEditor() {
11
+ this.tab('general', function () {
12
+ this.input('children', TextInputView);
13
+ });
14
+ }
15
+ });
16
+
17
+ editor$1.contentElementTypes.register('textBlock', {
18
+ configurationEditor: function configurationEditor() {
19
+ this.tab('general', function () {
20
+ this.input('children', TextAreaInputView);
21
+ });
22
+ }
23
+ });
24
+
25
+ editor$1.contentElementTypes.register('inlineImage', {
26
+ configurationEditor: function configurationEditor() {
27
+ this.tab('general', function () {
28
+ this.input('id', FileInputView, {
29
+ collection: 'image_files',
30
+ fileSelectionHandler: 'contentElementConfiguration'
31
+ });
32
+ this.group('ContentElementCaption');
33
+ this.group('ContentElementPosition');
34
+ });
35
+ }
36
+ });
37
+
38
+ editor$1.contentElementTypes.register('inlineVideo', {
39
+ configurationEditor: function configurationEditor() {
40
+ this.tab('general', function () {});
41
+ }
42
+ });
43
+
44
+ editor$1.contentElementTypes.register('inlineBeforeAfter', {
45
+ configurationEditor: function configurationEditor() {
46
+ this.tab('general', function () {
47
+ this.input('before_id', FileInputView, {
48
+ collection: 'image_files',
49
+ fileSelectionHandler: 'contentElementConfiguration',
50
+ positioning: false
51
+ });
52
+ this.input('before_label', TextInputView);
53
+ this.input('after_id', FileInputView, {
54
+ collection: 'image_files',
55
+ fileSelectionHandler: 'contentElementConfiguration',
56
+ positioning: false
57
+ });
58
+ this.input('after_label', TextInputView);
59
+ this.input('initial_slider_position', SliderInputView);
60
+ this.input('slider', CheckBoxInputView);
61
+ this.input('slider_handle', CheckBoxInputView, {
62
+ visibleBinding: 'slider'
63
+ });
64
+ this.input('slider_color', ColorInputView, {
65
+ visibleBinding: 'slider'
66
+ });
67
+ this.group('ContentElementPosition');
68
+ });
69
+ },
70
+ defaultConfig: {
71
+ slider: true,
72
+ slider_handle: true,
73
+ initial_slider_position: 50
74
+ }
75
+ });
76
+
77
+ editor$1.contentElementTypes.register('soundDisclaimer', {
78
+ configurationEditor: function configurationEditor() {
79
+ this.tab('general', function () {});
80
+ }
81
+ });
82
+
83
+ editor$1.contentElementTypes.register('videoEmbed', {
84
+ configurationEditor: function configurationEditor() {
85
+ this.tab('general', function () {
86
+ this.input('videoSource', UrlInputView, {
87
+ supportedHosts: ['http://youtu.be', 'https://youtu.be', 'http://www.youtube.com', 'https://www.youtube.com', 'http://vimeo.com', 'https://vimeo.com', 'http://www.facebook.com', 'https://www.facebook.com'],
88
+ displayPropertyName: 'videoSource',
89
+ required: true,
90
+ permitHttps: true
91
+ });
92
+ this.input('hideInfo', CheckBoxInputView);
93
+ this.input('hideControls', CheckBoxInputView);
94
+ this.input('aspectRatio', SelectInputView, {
95
+ values: ['wide', 'narrow', 'square', 'portrait']
96
+ });
97
+ this.group('ContentElementCaption');
98
+ this.group('ContentElementPosition');
99
+ });
100
+ }
101
+ });
102
+
103
+ var SidebarRouter = Marionette.AppRouter.extend({
104
+ appRoutes: {
105
+ 'scrolled/external_links/:id/': 'links',
106
+ 'scrolled/external_links/:id/:link_id': 'link'
107
+ }
108
+ });
109
+
110
+ function styleInject(css, ref) {
111
+ if ( ref === void 0 ) ref = {};
112
+ var insertAt = ref.insertAt;
113
+
114
+ if (!css || typeof document === 'undefined') { return; }
115
+
116
+ var head = document.head || document.getElementsByTagName('head')[0];
117
+ var style = document.createElement('style');
118
+ style.type = 'text/css';
119
+
120
+ if (insertAt === 'top') {
121
+ if (head.firstChild) {
122
+ head.insertBefore(style, head.firstChild);
123
+ } else {
124
+ head.appendChild(style);
125
+ }
126
+ } else {
127
+ head.appendChild(style);
128
+ }
129
+
130
+ if (style.styleSheet) {
131
+ style.styleSheet.cssText = css;
132
+ } else {
133
+ style.appendChild(document.createTextNode(css));
134
+ }
135
+ }
136
+
137
+ var css = ".SidebarListView-module_container__2j0sq {\n margin-top: 30px;\n}\n.SidebarListView-module_add__138Ey{\n border: 1px solid #1c86fe;\n border-radius: 3px;\n box-shadow: inset 0 1px 0 0 #b6d5f8;\n color: white !important;\n display: inline-block;\n font-size: 11px;\n font-weight: bold;\n background-color: #6aacf7;\n background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #6aacf7), color-stop(100%, #2b8efe));\n background-image: -webkit-linear-gradient(#6aacf7, #2b8efe);\n background-image: linear-gradient(#6aacf7, #2b8efe) !important;\n padding: 7px 18px;\n text-decoration: none !important;\n text-shadow: 0 1px 0 #067bff;\n background-clip: padding-box;\n padding-top: 5px;\n padding-bottom: 4px;\n padding-left: 12px\n}\n\n.SidebarListView-module_add__138Ey::before{\n font-family: 'entypo';\n content: \"\\2795\"\n}\n\n.SidebarListView-module_add__138Ey:hover:not(:disabled):not(.SidebarListView-module_disabled__2s_kN) {\n box-shadow: inset 0 1px 0 0 #87baf4;\n cursor: pointer;\n background-color: #559ff2;\n background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #559ff2), color-stop(100%, #1d86fc));\n background-image: -webkit-linear-gradient(#559ff2, #1d86fc);\n background-image: linear-gradient(#559ff2, #1d86fc)\n}\n\n.SidebarListView-module_add__138Ey:active:not(:disabled):not(.SidebarListView-module_disabled__2s_kN) {\n border: 1px solid #1c86fe;\n box-shadow: inset 0 0 8px 4px #0f7efb, inset 0 0 8px 4px #0f7efb, 0 1px 1px 0 #eee\n}\n\n.SidebarListView-module_header__fxwPU{\n display: 'block';\n}\n\n\n.SidebarListView-module_links_container__XDAeC {\n margin-top: 10px;\n}";
138
+ var styles = {"container":"SidebarListView-module_container__2j0sq","add":"SidebarListView-module_add__138Ey","disabled":"SidebarListView-module_disabled__2s_kN","header":"SidebarListView-module_header__fxwPU","links_container":"SidebarListView-module_links_container__XDAeC"};
139
+ styleInject(css);
140
+
141
+ var SidebarListView = Marionette.Layout.extend({
142
+ template: function template(data) {
143
+ return "\n <a class=\"back\">".concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.outline'), "</a>\n <a class=\"destroy\">").concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.destroy'), "</a>\n <div class=\"").concat(styles.container, "\">\n <label class=\"").concat(styles.header, "\">\n <span class=\"name\">").concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.name'), "</span>\n </label>\n <div class='").concat(styles.links_container, "'></div>\n <a class=\"").concat(styles.add, "\" href=\"\">").concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.add'), "</a>\n </div>\n ");
144
+ },
145
+ className: 'manage_external_links',
146
+ regions: {
147
+ linksContainer: '.' + styles.links_container
148
+ },
149
+ ui: cssModulesUtils.ui(styles, 'add', 'header'),
150
+ events: function events() {
151
+ var eventObject = {
152
+ 'click a.back': 'goBack',
153
+ 'click a.destroy': 'destroyElement'
154
+ };
155
+ eventObject['click a.' + styles.add] = 'addElement';
156
+ return eventObject;
157
+ },
158
+ initialize: function initialize(options) {
159
+ this.listenTo(options.contentElement.configuration, 'change', function () {
160
+ this.render();
161
+ });
162
+ },
163
+ onRender: function onRender() {
164
+ this.linksContainer.show(new ListView({
165
+ collection: this.model,
166
+ onEdit: _.bind(this.onEdit, this),
167
+ onRemove: _.bind(this.onRemove, this),
168
+ contentElement: this.options.contentElement
169
+ }));
170
+ },
171
+ goBack: function goBack() {
172
+ editor$1.navigate('', {
173
+ trigger: true
174
+ });
175
+ },
176
+ destroyElement: function destroyElement() {
177
+ if (confirm(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.confirm_delete'))) {
178
+ this.options.contentElement.destroy();
179
+ this.goBack();
180
+ }
181
+ },
182
+ addElement: function addElement() {
183
+ var newModel = this.model.addNewLink();
184
+ this.onEdit(newModel);
185
+ },
186
+ onEdit: function onEdit(linkModel) {
187
+ editor$1.navigate("/scrolled/external_links/".concat(this.options.contentElement.get('id'), "/").concat(linkModel.get('id')), {
188
+ trigger: true
189
+ });
190
+ },
191
+ onRemove: function onRemove(linkModel) {
192
+ if (confirm(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.confirm_delete_link'))) {
193
+ this.model.remove(linkModel);
194
+ }
195
+ }
196
+ });
197
+
198
+ var SidebarEditLinkView = Marionette.Layout.extend({
199
+ template: function template(data) {
200
+ return "\n <a class=\"back\">".concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.back'), "</a>\n <a class=\"destroy\">").concat(I18n.t('pageflow_scrolled.editor.content_elements.externalLinkList.destroy'), "</a>\n\n <div class='form_container'></div>\n ");
201
+ },
202
+ className: 'edit_external_link',
203
+ regions: {
204
+ formContainer: '.form_container'
205
+ },
206
+ events: {
207
+ 'click a.back': 'goBack',
208
+ 'click a.destroy': 'destroyLink'
209
+ },
210
+ initialize: function initialize(options) {},
211
+ onRender: function onRender() {
212
+ var configurationEditor = new ConfigurationEditorView({
213
+ model: this.model,
214
+ attributeTranslationKeyPrefixes: ['pageflow_scrolled.editor.content_elements.externalLinkList.attributes'],
215
+ tabTranslationKeyPrefix: 'pageflow_scrolled.editor.content_elements.externalLinkList.tabs'
216
+ });
217
+ var self = this;
218
+ configurationEditor.tab('edit_link', function () {
219
+ this.input('url', TextInputView, {
220
+ required: true
221
+ });
222
+ this.input('open_in_new_tab', CheckBoxInputView);
223
+ this.input('thumbnail', FileInputView, {
224
+ collection: 'image_files',
225
+ fileSelectionHandler: 'contentElement.externalLinks.link',
226
+ fileSelectionHandlerOptions: {
227
+ contentElementId: self.options.contentElement.get('id')
228
+ },
229
+ positioning: false
230
+ });
231
+ this.input('title', TextInputView, {
232
+ required: true
233
+ });
234
+ this.input('description', TextAreaInputView, {
235
+ size: 'short',
236
+ disableLinks: true
237
+ });
238
+ });
239
+ this.formContainer.show(configurationEditor);
240
+ },
241
+ goBack: function goBack() {
242
+ editor.navigate("/scrolled/external_links/".concat(this.options.contentElement.get('id'), "/"), {
243
+ trigger: true
244
+ });
245
+ },
246
+ destroyLink: function destroyLink() {
247
+ if (confirm('pageflow_scrolled.editor.content_elements.externalLinkList.confirm_delete_link')) {
248
+ this.options.collection.remove(this.model);
249
+ this.goBack();
250
+ }
251
+ }
252
+ });
253
+
254
+ var ExternalLinkModel = Backbone.Model.extend({
255
+ modelName: 'ExternalLink',
256
+ i18nKey: 'external_link',
257
+ mixins: [transientReferences],
258
+ initialize: function initialize(options) {},
259
+ thumbnailUrl: function thumbnailUrl() {
260
+ var image = this.collection.entry.imageFiles.getByPermaId(this.get('thumbnail'));
261
+ return image ? image.get('thumbnail_url') : '';
262
+ },
263
+ title: function title() {
264
+ return this.get('title');
265
+ }
266
+ });
267
+
268
+ var ExternalLinkCollection = Backbone.Collection.extend({
269
+ model: ExternalLinkModel,
270
+ initialize: function initialize(models, options) {
271
+ this.entry = options.entry;
272
+ this.configuration = options.configuration;
273
+ this.bind('change', this.updateConfiguration);
274
+ this.bind('add', this.updateConfiguration);
275
+ this.bind('remove', this.updateConfiguration);
276
+ },
277
+ modelId: function modelId(attrs) {
278
+ return attrs.id;
279
+ },
280
+ updateConfiguration: function updateConfiguration() {
281
+ var _this = this;
282
+
283
+ this.configuration.set('links', this.toJSON(), {
284
+ silent: true
285
+ });
286
+ setTimeout(function () {
287
+ //triggering change event inside this timeout block because otherwise due to
288
+ //some unknown reason page navigates to window.location.origin+window.location.pathname
289
+ //ignoring the hash thus causing the page to refresh.
290
+ _this.configuration.trigger('change');
291
+ }, 0);
292
+ },
293
+ addNewLink: function addNewLink() {
294
+ var newLink = {
295
+ id: this.length + 1,
296
+ title: '',
297
+ url: '',
298
+ thumbnail: '',
299
+ description: '',
300
+ open_in_new_tab: 1
301
+ };
302
+ this.add(newLink);
303
+ return this.get(this.length);
304
+ }
305
+ });
306
+
307
+ var SidebarController = Marionette.Controller.extend({
308
+ initialize: function initialize(options) {
309
+ this.region = options.region;
310
+ },
311
+ links: function links(id) {
312
+ var _this = this;
313
+
314
+ this.setModel(id); //if not done without timeout another empty tab view is shown in the sidebar
315
+ //to me it seems to be the problem of some method call ordering which gets fixed with this
316
+ //hack but in future it should be fixed without having to use setTimeout
317
+
318
+ setTimeout(function () {
319
+ _this.region.show(new SidebarListView({
320
+ model: _this.linksCollection,
321
+ contentElement: _this.model,
322
+ entry: _this.options.entry
323
+ }));
324
+ }, 0);
325
+ },
326
+ link: function link(id, link_id) {
327
+ var _this2 = this;
328
+
329
+ this.setModel(id);
330
+ setTimeout(function () {
331
+ _this2.region.show(new SidebarEditLinkView({
332
+ model: _this2.linksCollection.get(link_id),
333
+ collection: _this2.linksCollection,
334
+ contentElement: _this2.model,
335
+ entry: _this2.options.entry
336
+ }));
337
+ }, 0);
338
+ },
339
+ setModel: function setModel(id) {
340
+ this.model = this.options.entry.contentElements.get(id);
341
+ var configuration = this.model.configuration;
342
+
343
+ if (!configuration.get('links')) {
344
+ configuration.set('links', []);
345
+ }
346
+
347
+ this.linksCollection = new ExternalLinkCollection(configuration.get('links'), {
348
+ entry: this.options.entry,
349
+ configuration: configuration
350
+ });
351
+ }
352
+ });
353
+
354
+ //router defines the URL hash path mapping and controller provides functions for the paths
355
+
356
+ editor$1.registerSideBarRouting({
357
+ router: SidebarRouter,
358
+ controller: SidebarController
359
+ }); // register external link list content element configuration editor for sidebar
360
+
361
+ editor$1.contentElementTypes.register('externalLinkList', {
362
+ configurationEditor: function configurationEditor() {
363
+ this.tab('general', function () {
364
+ var externalListModel = this.model.parent; //redirect to special hash path that is specific to external links only
365
+
366
+ editor$1.navigate("/scrolled/external_links/".concat(externalListModel.get('id'), "/"), {
367
+ trigger: true
368
+ });
369
+ });
370
+ }
371
+ }); // register file handler for thumbnail of external link
372
+
373
+ editor$1.registerFileSelectionHandler('contentElement.externalLinks.link', function (options) {
374
+ var contentElement = options.entry.contentElements.get(options.contentElementId);
375
+ var links = contentElement.configuration.get('links');
376
+
377
+ this.call = function (file) {
378
+ var link = links.find(function (link) {
379
+ return link.id == options.id;
380
+ });
381
+ link.thumbnail = file.get('perma_id');
382
+ contentElement.configuration.set('links', links);
383
+ contentElement.configuration.trigger('change', contentElement.configuration);
384
+ };
385
+
386
+ this.getReferer = function () {
387
+ return '/scrolled/external_links/' + contentElement.id + '/' + options.id;
388
+ };
389
+ });
390
+
391
+ var DatawrapperAdView = Marionette.ItemView.extend({
392
+ template: function template(data) {
393
+ return "\n <form action=\"https://datawrapper.de/chart/create\" method=\"POST\" target=\"_blank\">\n <input type=\"hidden\" name=\"theme\" value=\"pageflow\" />\n <input type=\"submit\" value=\"".concat(I18n$1.t('pageflow_scrolled.editor.content_elements.dataWrapperChart.attributes.create_chart.label'), "\" />\n </form>\n ");
394
+ },
395
+ className: 'datawrapper_ad'
396
+ });
397
+
398
+ editor$1.contentElementTypes.register('dataWrapperChart', {
399
+ configurationEditor: function configurationEditor() {
400
+ this.tab('general', function () {
401
+ this.input('url', UrlInputView, {
402
+ supportedHosts: ['http://cf.datawrapper.de', 'https://cf.datawrapper.de', 'http://datawrapper.dwcdn.de', 'https://datawrapper.dwcdn.de', 'http://datawrapper.dwcdn.net', 'https://datawrapper.dwcdn.net', 'http://charts.datawrapper.de', 'https://charts.datawrapper.de'],
403
+ displayPropertyName: 'url',
404
+ required: true,
405
+ permitHttps: true
406
+ });
407
+ this.view(DatawrapperAdView);
408
+ });
409
+ }
410
+ });