pageflow 16.0.0 → 16.1.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +210 -33
  3. data/README.md +0 -1
  4. data/Rakefile +1 -1
  5. data/admins/pageflow/entry.rb +0 -1
  6. data/admins/pageflow/sites.rb +3 -0
  7. data/app/assets/javascripts/pageflow/dist/ui.js +298 -72
  8. data/app/assets/stylesheets/pageflow/admin/permalink_input.scss +10 -0
  9. data/app/assets/stylesheets/pageflow/editor/drop_down_button.scss +6 -1
  10. data/app/assets/stylesheets/pageflow/editor/file_thumbnails.scss +4 -0
  11. data/app/assets/stylesheets/pageflow/editor/help.scss +3 -3
  12. data/app/assets/stylesheets/pageflow/editor/info_box.scss +7 -0
  13. data/app/assets/stylesheets/pageflow/editor/inputs/file_input.scss +0 -5
  14. data/app/assets/stylesheets/pageflow/ui/forms.scss +1 -1
  15. data/app/controllers/pageflow/chapters_controller.rb +2 -2
  16. data/app/controllers/pageflow/editor/files_controller.rb +1 -1
  17. data/app/controllers/pageflow/entries_controller.rb +10 -0
  18. data/app/controllers/pageflow/feeds_controller.rb +18 -0
  19. data/app/controllers/pageflow/pages_controller.rb +2 -2
  20. data/app/controllers/pageflow/sitemaps_controller.rb +15 -0
  21. data/app/controllers/pageflow/storylines_controller.rb +2 -2
  22. data/app/helpers/pageflow/entries_helper.rb +2 -1
  23. data/app/helpers/pageflow/feeds_helper.rb +66 -0
  24. data/app/helpers/pageflow/page_types_helper.rb +9 -9
  25. data/app/inputs/pageflow_permalink_input.rb +15 -3
  26. data/app/models/concerns/pageflow/reusable_file.rb +3 -3
  27. data/app/models/pageflow/account.rb +8 -0
  28. data/app/models/pageflow/audio_file_url_templates.rb +2 -1
  29. data/app/models/pageflow/draft_entry.rb +1 -1
  30. data/app/models/pageflow/entries_feed.rb +32 -0
  31. data/app/models/pageflow/image_file.rb +14 -3
  32. data/app/models/pageflow/membership.rb +3 -2
  33. data/app/models/pageflow/other_file.rb +5 -0
  34. data/app/models/pageflow/other_file_url_templates.rb +16 -0
  35. data/app/models/pageflow/published_entry.rb +6 -0
  36. data/app/models/pageflow/revision.rb +4 -0
  37. data/app/models/pageflow/site.rb +8 -0
  38. data/app/models/pageflow/sitemaps.rb +13 -0
  39. data/app/models/pageflow/used_file.rb +2 -2
  40. data/app/models/pageflow/video_file_url_templates.rb +3 -1
  41. data/app/models/pageflow/widget.rb +9 -1
  42. data/app/views/admin/entries/_permalink_inputs.html.erb +1 -2
  43. data/app/views/admin/sites/_attributes_table.html.arb +3 -0
  44. data/app/views/admin/sites/_fields.html.erb +6 -0
  45. data/app/views/components/pageflow/admin/extensible_attributes_table.rb +8 -2
  46. data/app/views/components/pageflow/admin/sites_tab.rb +3 -0
  47. data/app/views/pageflow/editor/config/_seeds.json.jbuilder +1 -0
  48. data/app/views/pageflow/feeds/index.atom.builder +20 -0
  49. data/app/views/pageflow/sitemaps/index.xml.builder +9 -0
  50. data/config/initializers/features.rb +1 -0
  51. data/config/initializers/paperclip.rb +4 -0
  52. data/config/locales/de.yml +27 -6
  53. data/config/locales/en.yml +30 -4
  54. data/config/routes.rb +3 -0
  55. data/config/spring.rb +1 -1
  56. data/db/migrate/20230120092923_create_other_files.rb +23 -0
  57. data/db/migrate/20230323115745_add_feeds_enabled_to_sites.rb +5 -0
  58. data/db/migrate/20230323154323_add_sitemap_enabled_to_sites.rb +5 -0
  59. data/db/migrate/20230331103823_add_title_to_sites.rb +5 -0
  60. data/db/migrate/20230405103612_add_custom_feed_url_to_sites.rb +5 -0
  61. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +445 -109
  62. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +26 -3
  63. data/entry_types/paged/app/controllers/pageflow_paged/editor/entries_controller.rb +0 -2
  64. data/entry_types/paged/app/controllers/pageflow_paged/entries_controller.rb +1 -0
  65. data/entry_types/paged/app/views/pageflow_paged/entries/show.html.erb +1 -0
  66. data/entry_types/paged/config/initializers/features.rb +0 -1
  67. data/entry_types/paged/lib/pageflow_paged/engine.rb +17 -1
  68. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +2 -2
  69. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +3 -4
  70. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +13 -6
  71. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +2 -0
  72. data/entry_types/scrolled/app/helpers/pageflow_scrolled/cache_helper.rb +11 -0
  73. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/entry_json_seed_helper.rb +42 -0
  74. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +3 -0
  75. data/entry_types/scrolled/app/helpers/pageflow_scrolled/packs_helper.rb +31 -10
  76. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +9 -1
  77. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +3 -1
  78. data/entry_types/scrolled/app/models/pageflow_scrolled/chapter.rb +23 -0
  79. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +6 -1
  80. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_seed.json.jbuilder +1 -5
  81. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/sections/_section_with_content_elements.json.jbuilder +10 -0
  82. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +44 -41
  83. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_consent_vendors.json.jbuilder +16 -0
  84. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +3 -0
  85. data/entry_types/scrolled/config/initializers/features.rb +5 -0
  86. data/entry_types/scrolled/config/locales/consent_widget.de.yml +4 -0
  87. data/entry_types/scrolled/config/locales/consent_widget.en.yml +4 -0
  88. data/entry_types/scrolled/config/locales/de.yml +189 -8
  89. data/entry_types/scrolled/config/locales/en.yml +207 -2
  90. data/entry_types/scrolled/config/routes.rb +4 -0
  91. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +97 -5
  92. data/entry_types/scrolled/lib/pageflow_scrolled/additional_seed_data.rb +1 -1
  93. data/entry_types/scrolled/lib/pageflow_scrolled/configuration.rb +96 -0
  94. data/entry_types/scrolled/lib/pageflow_scrolled/content_element_consent_vendors.rb +38 -0
  95. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +17 -1
  96. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +24 -0
  97. data/entry_types/scrolled/lib/pageflow_scrolled/react_widget_type.rb +6 -1
  98. data/entry_types/scrolled/lib/tasks/pageflow_scrolled/storybook.rake +1 -2
  99. data/entry_types/scrolled/package/contentElements-editor.js +307 -22
  100. data/entry_types/scrolled/package/contentElements-frontend.css +1 -1
  101. data/entry_types/scrolled/package/contentElements-frontend.js +690 -71
  102. data/entry_types/scrolled/package/editor.js +616 -220
  103. data/entry_types/scrolled/package/frontend/{EditableInlineText.module-14c7b097.js → EditableInlineText.module-fa9e3aff.js} +1669 -1674
  104. data/entry_types/scrolled/package/frontend/PhonePlatformContext-10a1d600.js +32 -0
  105. data/entry_types/scrolled/package/frontend/ToggleFullscreenCornerButton-727cce0d.js +107 -0
  106. data/entry_types/scrolled/package/frontend/Viewer-169e14ca.js +154 -0
  107. data/entry_types/scrolled/package/frontend/{Viewer-b6becc57.js → Viewer-ee1aa590.js} +32 -161
  108. data/entry_types/scrolled/package/frontend/arrowRight-92a34ccc.js +77 -0
  109. data/entry_types/scrolled/package/frontend/{components-b3160dd7.js → components-4a09bfa3.js} +185 -45
  110. data/entry_types/scrolled/package/frontend/{PhonePlatformContext-f6093cc6.js → i18n-ddd92820.js} +149 -107
  111. data/entry_types/scrolled/package/frontend/index-02378634.js +118 -0
  112. data/entry_types/scrolled/package/frontend/index.css +1 -1
  113. data/entry_types/scrolled/package/frontend/index.js +206 -54
  114. data/entry_types/scrolled/package/frontend/useContentElementEditorState-63045393.js +52 -0
  115. data/entry_types/scrolled/package/package.json +2 -1
  116. data/entry_types/scrolled/package/testHelpers.js +9 -2
  117. data/entry_types/scrolled/package/values/colors.module.css +15 -0
  118. data/entry_types/scrolled/package/widgets/consentBar.css +1 -0
  119. data/entry_types/scrolled/package/widgets/consentBar.js +426 -0
  120. data/entry_types/scrolled/package/widgets/defaultNavigation.css +1 -1
  121. data/lib/generators/pageflow/resque/resque_generator.rb +1 -1
  122. data/lib/pageflow/ability_mixin.rb +5 -5
  123. data/lib/pageflow/active_admin_can_can_fix.rb +2 -2
  124. data/lib/pageflow/built_in_file_type.rb +7 -0
  125. data/lib/pageflow/configuration.rb +21 -0
  126. data/lib/pageflow/engine.rb +60 -39
  127. data/lib/pageflow/entry_export_import/revision_serialization.rb +1 -1
  128. data/lib/pageflow/file_type.rb +2 -2
  129. data/lib/pageflow/global_config_api.rb +2 -2
  130. data/lib/pageflow/nested_revision_component.rb +23 -5
  131. data/lib/pageflow/rails_version.rb +19 -0
  132. data/lib/pageflow/seeds.rb +10 -7
  133. data/lib/pageflow/version.rb +1 -1
  134. data/lib/pageflow/widget_types.rb +4 -0
  135. data/package/config/webpack5.js +14 -0
  136. data/package/editor.js +141 -30
  137. data/package/frontend.js +26 -2
  138. data/package/testHelpers.js +1 -1
  139. data/package/ui.js +296 -71
  140. data/spec/factories/entries.rb +17 -3
  141. data/spec/factories/sites.rb +3 -0
  142. data/vendor/assets/javascripts/iscroll.js +4 -7
  143. metadata +65 -49
  144. data/app/helpers/pageflow/admin/permalinks_helper.rb +0 -15
  145. data/entry_types/scrolled/package/frontend/arrowRight-78a7cee4.js +0 -42
@@ -31,6 +31,8 @@ require 'pageflow_paged'
31
31
  require 'pageflow_scrolled'
32
32
  require 'symmetric-encryption'
33
33
 
34
+ require 'pageflow/rails_version'
35
+
34
36
  if Gem::Specification.find_all_by_name('pageflow-react', '>= 0.0').any?
35
37
  fail('The pageflow-react gem has been merged into the pageflow gem. ' \
36
38
  'See the pageflow changelog for update instructions.')
@@ -41,44 +43,63 @@ module Pageflow
41
43
  class Engine < ::Rails::Engine
42
44
  isolate_namespace Pageflow
43
45
 
44
- config.paths.add('app/views/components', autoload: true)
45
- config.paths.add('lib', autoload: true)
46
-
47
- def eager_load!
48
- # Manually eager load `lib/pageflow` as the least bad option:
49
- #
50
- # - Autoload paths are not eager loaded in production.
51
- #
52
- # - `lib` cannot be an eager load path since otherwise templates
53
- # in `lib/generators` are also executed.
54
- #
55
- # - `lib/pageflow` cannot be an eager load path since eager load
56
- # paths are automatically used as autoload paths. That way
57
- # `lib/pageflow/admin/something.rb` could be autoloaded via
58
- # `Admin::Something`.
59
- #
60
- # - Using `require` in `lib/pageflow.rb` disables code
61
- # reloading.
62
- #
63
- # - Using `require_dependency` in `lib/pageflow.rb` does not
64
- # activate code reloading either since it requires the
65
- # autoload path to be set up correctly, which only happens
66
- # during initialization.
67
- super
68
-
69
- lib_path = config.root.join('lib')
70
- matcher = %r{\A#{Regexp.escape(lib_path.to_s)}/(.*)\.rb\Z}
71
-
72
- already_required_files = [
73
- 'pageflow/engine',
74
- 'pageflow/global_config_api',
75
- 'pageflow/news_item_api',
76
- 'pageflow/version'
77
- ]
78
-
79
- Dir.glob("#{lib_path}/pageflow/**/*.rb").sort.each do |file|
80
- logical_path = file.sub(matcher, '\1')
81
- require_dependency(logical_path) unless already_required_files.include?(logical_path)
46
+ if Pageflow::RailsVersion.experimental?
47
+ config.autoload_paths << root.join('app/views/components')
48
+ config.eager_load_paths << root.join('app/views/components')
49
+
50
+ lib = root.join('lib')
51
+
52
+ config.autoload_paths << lib
53
+ config.eager_load_paths << lib
54
+
55
+ initializer 'pageflow.autoloading' do
56
+ Rails.autoloaders.main.ignore(
57
+ lib.join('generators'),
58
+ lib.join('tasks'),
59
+ lib.join('pageflow/paperclip_processors'),
60
+ lib.join('pageflow/version.rb')
61
+ )
62
+ end
63
+ else
64
+ config.paths.add('app/views/components', autoload: true)
65
+ config.paths.add('lib', autoload: true)
66
+
67
+ def eager_load!
68
+ # Manually eager load `lib/pageflow` as the least bad option:
69
+ #
70
+ # - Autoload paths are not eager loaded in production.
71
+ #
72
+ # - `lib` cannot be an eager load path since otherwise templates
73
+ # in `lib/generators` are also executed.
74
+ #
75
+ # - `lib/pageflow` cannot be an eager load path since eager load
76
+ # paths are automatically used as autoload paths. That way
77
+ # `lib/pageflow/admin/something.rb` could be autoloaded via
78
+ # `Admin::Something`.
79
+ #
80
+ # - Using `require` in `lib/pageflow.rb` disables code
81
+ # reloading.
82
+ #
83
+ # - Using `require_dependency` in `lib/pageflow.rb` does not
84
+ # activate code reloading either since it requires the
85
+ # autoload path to be set up correctly, which only happens
86
+ # during initialization.
87
+ super
88
+
89
+ lib_path = config.root.join('lib')
90
+ matcher = %r{\A#{Regexp.escape(lib_path.to_s)}/(.*)\.rb\Z}
91
+
92
+ already_required_files = [
93
+ 'pageflow/engine',
94
+ 'pageflow/global_config_api',
95
+ 'pageflow/news_item_api',
96
+ 'pageflow/version'
97
+ ]
98
+
99
+ Dir.glob("#{lib_path}/pageflow/**/*.rb").sort.each do |file|
100
+ logical_path = file.sub(matcher, '\1')
101
+ require_dependency(logical_path) unless already_required_files.include?(logical_path)
102
+ end
82
103
  end
83
104
  end
84
105
 
@@ -106,7 +127,7 @@ module Pageflow
106
127
  end
107
128
 
108
129
  initializer 'pageflow.factories', after: 'factory_bot.set_factory_paths' do
109
- if Pageflow.configured? && defined?(FactoryBot)
130
+ if defined?(FactoryBot)
110
131
  FactoryBot.definition_file_paths.unshift(Engine.root.join('spec', 'factories'))
111
132
  end
112
133
  end
@@ -28,7 +28,7 @@ module Pageflow
28
28
  end
29
29
 
30
30
  def import(data, options)
31
- Import.new(options).perform(data)
31
+ Import.new(**options).perform(data)
32
32
  end
33
33
 
34
34
  private
@@ -123,11 +123,11 @@ module Pageflow
123
123
  @css_background_image_class_prefix || model.model_name.singular
124
124
  end
125
125
 
126
- def css_background_image_urls_for(file, options)
126
+ def css_background_image_urls_for(file, **options)
127
127
  if call_arity(css_background_image_urls) == 1
128
128
  css_background_image_urls.call(file)
129
129
  else
130
- css_background_image_urls.call(file, options)
130
+ css_background_image_urls.call(file, **options)
131
131
  end
132
132
  end
133
133
 
@@ -87,8 +87,6 @@ module Pageflow
87
87
  # coniguration is now complete.
88
88
  def finalize!
89
89
  @finalized = true
90
- configure!
91
- @config.lint!
92
90
  end
93
91
 
94
92
  # @api private
@@ -103,6 +101,8 @@ module Pageflow
103
101
  @after_global_configure_blocks.each do |block|
104
102
  block.call(@config)
105
103
  end
104
+
105
+ @config.lint!
106
106
  end
107
107
 
108
108
  private
@@ -14,10 +14,10 @@ module Pageflow
14
14
  end
15
15
 
16
16
  # @api private
17
- def copy_nested_revision_component_to(record)
17
+ def copy_nested_revision_component_to(record, reset_perma_ids: false)
18
18
  nested_revision_component_collection_names.each do |collection_name|
19
19
  send(collection_name).each do |nested|
20
- nested.copy_to(record.send(collection_name))
20
+ nested.copy_to(record.send(collection_name), reset_perma_ids: reset_perma_ids)
21
21
  end
22
22
  end
23
23
  end
@@ -38,12 +38,30 @@ module Pageflow
38
38
  extend ActiveSupport::Concern
39
39
  include Container
40
40
 
41
+ def duplicate
42
+ copy_with(reset_perma_ids: true) do |record|
43
+ yield record if block_given?
44
+ record.save!
45
+ end
46
+ end
47
+
41
48
  # @api private
42
- def copy_to(collection)
49
+ def copy_to(collection, reset_perma_ids: false)
50
+ copy_with(reset_perma_ids: reset_perma_ids) do |record|
51
+ collection << record
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def copy_with(reset_perma_ids:)
43
58
  record = dup
44
- collection << record
59
+ record.perma_id = nil if reset_perma_ids && record.respond_to?(:perma_id=)
60
+
61
+ yield record
62
+ copy_nested_revision_component_to(record, reset_perma_ids: reset_perma_ids)
45
63
 
46
- copy_nested_revision_component_to(record)
64
+ record
47
65
  end
48
66
  end
49
67
  end
@@ -0,0 +1,19 @@
1
+ module Pageflow
2
+ module RailsVersion
3
+ extend self
4
+
5
+ def detect
6
+ from_env || '5.2.0'
7
+ end
8
+
9
+ def experimental?
10
+ detect != '5.2.0'
11
+ end
12
+
13
+ private
14
+
15
+ def from_env
16
+ ENV['PAGEFLOW_RAILS_VERSION'] if ENV['PAGEFLOW_RAILS_VERSION'] != ''
17
+ end
18
+ end
19
+ end
@@ -97,16 +97,18 @@ module Pageflow
97
97
  end
98
98
  end
99
99
 
100
- # Create a sample {Entry} with some chapter and pages if no
101
- # entry with that title exists in the given account.
100
+ # Create a sample {Entry} with some chapter, pages, and optional
101
+ # text if no entry with that title exists in the given account.
102
102
  #
103
103
  # @param [Hash] attributes attributes to override defaults
104
104
  # @option attributes [Account] :account required
105
- # @option attributes [title] :title required
105
+ # @option attributes [String] :title required
106
+ # @option attributes [String] :text optional
106
107
  # @yield [entry] a block to be called before the entry is saved
107
108
  # @return [Entry] newly created entry
108
109
  def sample_entry(attributes)
109
110
  entry = Entry.where(attributes.slice(:account, :title)).first
111
+ page_text = attributes.delete(:text) { |_| '' }
110
112
 
111
113
  if entry.nil?
112
114
  entry = Entry.create!(attributes) do |created_entry|
@@ -117,13 +119,14 @@ module Pageflow
117
119
  end
118
120
 
119
121
  storyline = entry.draft.storylines.first
120
-
121
122
  chapter = storyline.chapters.create!(title: 'Chapter 1', position: 0)
122
- chapter.pages.create!(template: 'background_image')
123
- chapter.pages.create!(template: 'background_image')
123
+ chapter.pages.create!(template: 'background_image',
124
+ configuration: {text: page_text})
125
+ chapter.pages.create!(template: 'background_image',
126
+ configuration: {text: page_text})
124
127
 
125
128
  chapter = storyline.chapters.create!(title: 'Chapter 2', position: 1)
126
- chapter.pages.create!(template: 'video')
129
+ chapter.pages.create!(template: 'video', configuration: {text: page_text})
127
130
  end
128
131
 
129
132
  entry
@@ -1,3 +1,3 @@
1
1
  module Pageflow
2
- VERSION = '16.0.0'.freeze
2
+ VERSION = '16.1.0'.freeze
3
3
  end
@@ -41,6 +41,10 @@ module Pageflow
41
41
  @widget_types.fetch(name, &block)
42
42
  end
43
43
 
44
+ def type_name?(name)
45
+ @widget_types.key?(name)
46
+ end
47
+
44
48
  def default_configuration(name)
45
49
  @default_configurations[name]
46
50
  end
@@ -0,0 +1,14 @@
1
+ module.exports = {
2
+ externals: {
3
+ 'backbone': 'Backbone',
4
+ 'backbone.babysitter': 'Backbone.ChildViewContainer',
5
+ 'cocktail': 'Cocktail',
6
+ 'jquery': 'jQuery',
7
+ 'jquery-ui': 'jQuery',
8
+ 'jquery.minicolors': 'jQuery',
9
+ 'underscore': '_',
10
+ 'backbone.marionette': 'Backbone.Marionette',
11
+ 'iscroll': 'IScroll',
12
+ 'wysihtml5': 'wysihtml5'
13
+ }
14
+ };
data/package/editor.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import Backbone from 'backbone';
2
2
  import _ from 'underscore';
3
- import { Object as Object$1, ConfigurationEditorTabView, TextInputView, UrlDisplayView, TabsView, ConfigurationEditorView, CollectionView, tooltipContainer, SelectInputView, inputView, TextAreaInputView, CheckBoxGroupInputView, i18nUtils, TableView, TextTableCellView, PresenceTableCellView, SortableCollectionView, DeleteRowTableCellView, CheckBoxInputView, SliderInputView, IconTableCellView } from 'pageflow/ui';
3
+ import { Object as Object$1, ConfigurationEditorTabView, TextInputView, UrlDisplayView, TabsView, ConfigurationEditorView, CollectionView, tooltipContainer, SelectInputView, inputView, TextAreaInputView, CheckBoxGroupInputView, i18nUtils, TableView, TextTableCellView, PresenceTableCellView, SortableCollectionView, attributeBinding, DeleteRowTableCellView, CheckBoxInputView, SliderInputView, IconTableCellView } from 'pageflow/ui';
4
4
  export * from 'pageflow/ui';
5
5
  import Cocktail from 'cocktail';
6
6
  import I18n$1 from 'i18n-js';
7
7
  import Marionette from 'backbone.marionette';
8
8
  import $ from 'jquery';
9
9
  import { browser, features, Audio, events } from 'pageflow/frontend';
10
+ import 'jquery-ui';
10
11
 
11
12
  (function () {
12
13
  var sync = Backbone.sync;
@@ -234,7 +235,7 @@ var UnmatchedUploadError = UploadError.extend({
234
235
  });
235
236
  var validFileTypeTranslationList = {
236
237
  validFileTypeTranslations: function validFileTypeTranslations(validFileTypes) {
237
- return _.map(validFileTypes, function (validFileType) {
238
+ return validFileTypes.map(function (validFileType) {
238
239
  return I18n$1.t('activerecord.models.' + validFileType.i18nKey + '.other');
239
240
  }).join(', ');
240
241
  }
@@ -264,7 +265,7 @@ var InvalidNestedTypeError = UploadError.extend({
264
265
  initialize: function initialize(upload, options) {
265
266
  var editor = options.editor;
266
267
  var fileType = options.fileType;
267
- var validFileTypes = editor.nextUploadTargetFile.fileType().nestedFileTypes.fileTypes;
268
+ var validFileTypes = editor.nextUploadTargetFile.fileType().nestedFileTypes;
268
269
  var validFileTypeTranslations = this.validFileTypeTranslations(validFileTypes);
269
270
  var typeI18nKey = fileType.i18nKey;
270
271
  var typeSingularTranslation = I18n$1.t('activerecord.models.' + typeI18nKey + '.one');
@@ -578,22 +579,31 @@ var FileTypes = Object$1.extend({
578
579
  this.clientSideConfigModifications[name].push(config);
579
580
  },
580
581
  setup: function setup(serverSideConfigs) {
582
+ var _this = this;
583
+
581
584
  var clientSideConfigs = this.clientSideConfigs;
582
585
  this._setup = true;
583
- this.collection = new FileTypesCollection(_.map(serverSideConfigs, function (serverSideConfig) {
586
+
587
+ var configs = _.chain(serverSideConfigs).map(function (serverSideConfig) {
584
588
  var clientSideConfig = clientSideConfigs[serverSideConfig.collectionName];
585
589
 
586
590
  if (!clientSideConfig) {
587
591
  throw 'Missing client side config for file type "' + serverSideConfig.collectionName + '"';
588
592
  }
589
593
 
590
- _(this.clientSideConfigModifications[serverSideConfig.collectionName]).each(function (modification) {
594
+ _(_this.clientSideConfigModifications[serverSideConfig.collectionName]).each(function (modification) {
591
595
  this.lintModification(modification, serverSideConfig.collectionName);
592
596
  this.applyModification(clientSideConfig, modification);
593
- }, this);
597
+ }, _this);
594
598
 
595
- return new FileType(_.extend({}, serverSideConfig, clientSideConfig));
596
- }, this));
599
+ return _.extend({}, serverSideConfig, clientSideConfig);
600
+ }).sortBy(function (config) {
601
+ return config.priority || 10;
602
+ }).value();
603
+
604
+ this.collection = new FileTypesCollection(_.map(configs, function (config) {
605
+ return new FileType(config);
606
+ }));
597
607
  var those = this;
598
608
 
599
609
  _.map(serverSideConfigs, function (serverSideConfig) {
@@ -1107,10 +1117,12 @@ var EditorApi = Object$1.extend(
1107
1117
  * Trigger selection of the given file type with the given
1108
1118
  * handler. Payload hash is passed to selection handler as options.
1109
1119
  *
1110
- * @param {string|{name: string, filter: string}} fileType
1120
+ * @param {string|{name: string, filter: string}|{defaultTab: string, filter: string}} fileType
1111
1121
  * Either collection name of a file type or and object containing
1112
1122
  * the collection name a file type and a the name of a file type
1113
- * filter.
1123
+ * filter or an object containingn a defaultTab property that controls
1124
+ * which tab will visible initially, while allowing selecting files of
1125
+ * any type.
1114
1126
  *
1115
1127
  * @param {string} handlerName
1116
1128
  * The name of a handler registered via {@link
@@ -1136,7 +1148,7 @@ var EditorApi = Object$1.extend(
1136
1148
  };
1137
1149
  }
1138
1150
 
1139
- this.navigate('/files/' + fileType.name + '?handler=' + handlerName + '&payload=' + encodeURIComponent(JSON.stringify(payload)) + (fileType.filter ? '&filter=' + fileType.filter : ''), {
1151
+ this.navigate('/files/' + (fileType.defaultTab ? "".concat(fileType.defaultTab, ":default") : fileType.name) + '?handler=' + handlerName + '&payload=' + encodeURIComponent(JSON.stringify(payload)) + (fileType.filter ? '&filter=' + fileType.filter : ''), {
1140
1152
  trigger: true
1141
1153
  });
1142
1154
  },
@@ -3555,6 +3567,13 @@ var ForeignKeySubsetCollection = SubsetCollection.extend({
3555
3567
  var parent = options.parent;
3556
3568
  var parentModel = options.parentModel;
3557
3569
  this.autoConsolidatePositions = options.autoConsolidatePositions;
3570
+ this.listenTo(this, 'add', function (model) {
3571
+ if (options.parentReferenceAttribute) {
3572
+ model[options.parentReferenceAttribute] = parentModel;
3573
+ }
3574
+
3575
+ model.set(options.foreignKeyAttribute, parentModel.id);
3576
+ });
3558
3577
  SubsetCollection.prototype.constructor.call(this, {
3559
3578
  parent: parent,
3560
3579
  parentModel: parentModel,
@@ -3565,13 +3584,6 @@ var ForeignKeySubsetCollection = SubsetCollection.extend({
3565
3584
  return item.get('position');
3566
3585
  }
3567
3586
  });
3568
- this.listenTo(this, 'add', function (model) {
3569
- if (options.parentReferenceAttribute) {
3570
- model[options.parentReferenceAttribute] = parentModel;
3571
- }
3572
-
3573
- model.set(options.foreignKeyAttribute, parentModel.id);
3574
- });
3575
3587
  this.listenTo(parentModel, 'destroy dependentDestroy', function () {
3576
3588
  this.invoke('trigger', 'dependentDestroy');
3577
3589
  this.clear();
@@ -3824,6 +3836,64 @@ var SidebarRouter = Marionette.AppRouter.extend({
3824
3836
  }
3825
3837
  });
3826
3838
 
3839
+ function _arrayWithHoles(arr) {
3840
+ if (Array.isArray(arr)) return arr;
3841
+ }
3842
+
3843
+ function _iterableToArrayLimit(arr, i) {
3844
+ if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
3845
+ var _arr = [];
3846
+ var _n = true;
3847
+ var _d = false;
3848
+ var _e = undefined;
3849
+
3850
+ try {
3851
+ for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
3852
+ _arr.push(_s.value);
3853
+
3854
+ if (i && _arr.length === i) break;
3855
+ }
3856
+ } catch (err) {
3857
+ _d = true;
3858
+ _e = err;
3859
+ } finally {
3860
+ try {
3861
+ if (!_n && _i["return"] != null) _i["return"]();
3862
+ } finally {
3863
+ if (_d) throw _e;
3864
+ }
3865
+ }
3866
+
3867
+ return _arr;
3868
+ }
3869
+
3870
+ function _arrayLikeToArray(arr, len) {
3871
+ if (len == null || len > arr.length) len = arr.length;
3872
+
3873
+ for (var i = 0, arr2 = new Array(len); i < len; i++) {
3874
+ arr2[i] = arr[i];
3875
+ }
3876
+
3877
+ return arr2;
3878
+ }
3879
+
3880
+ function _unsupportedIterableToArray(o, minLen) {
3881
+ if (!o) return;
3882
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
3883
+ var n = Object.prototype.toString.call(o).slice(8, -1);
3884
+ if (n === "Object" && o.constructor) n = o.constructor.name;
3885
+ if (n === "Map" || n === "Set") return Array.from(n);
3886
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
3887
+ }
3888
+
3889
+ function _nonIterableRest() {
3890
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3891
+ }
3892
+
3893
+ function _slicedToArray(arr, i) {
3894
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
3895
+ }
3896
+
3827
3897
  function template$3(data) {
3828
3898
  var __t, __p = '';
3829
3899
  __p += '<a class="back">' +
@@ -4514,6 +4584,13 @@ return __p
4514
4584
  * Require click to open menu. By default, menu opens on when the
4515
4585
  * mouse enters the button.
4516
4586
  *
4587
+ * @param {String} [options.alignMenu]
4588
+ * "right" to align menu on the right. Aligned on the left by
4589
+ * default.
4590
+ *
4591
+ * @param {String} [options.buttonClassName]
4592
+ * CSS class name for button element.
4593
+ *
4517
4594
  * ## Item Models
4518
4595
  *
4519
4596
  * The following model attributes can be used to control the
@@ -4553,7 +4630,9 @@ var DropDownButtonView = Marionette.ItemView.extend({
4553
4630
  this.$el.toggleClass('full_width', !!this.options.fullWidth);
4554
4631
  this.ui.button.toggleClass('has_icon_and_text', !!this.options.label);
4555
4632
  this.ui.button.toggleClass('has_icon_only', !this.options.label);
4633
+ this.ui.button.toggleClass('ellipsis_icon', !!this.options.ellipsisIcon);
4556
4634
  this.ui.button.text(this.options.label);
4635
+ this.ui.button.addClass(this.options.buttonClassName);
4557
4636
  this.ui.menu.append(this.subview(new DropDownButtonItemListView({
4558
4637
  items: this.options.items
4559
4638
  })).el);
@@ -4577,7 +4656,7 @@ var DropDownButtonView = Marionette.ItemView.extend({
4577
4656
  var offset = this.$el.offset();
4578
4657
  this.ui.menu.css({
4579
4658
  top: offset.top + this.$el.height(),
4580
- left: offset.left,
4659
+ left: this.options.alignMenu === 'right' ? offset.left + this.$el.width() - this.ui.menu.outerWidth() : offset.left,
4581
4660
  width: this.options.fullWidth ? this.$el.width() : null
4582
4661
  });
4583
4662
  },
@@ -4712,6 +4791,7 @@ var FileInputView = Marionette.ItemView.extend({
4712
4791
  if (dropDownMenuItems.length) {
4713
4792
  this.appendSubview(new DropDownButtonView({
4714
4793
  items: dropDownMenuItems,
4794
+ ellipsisIcon: true,
4715
4795
  openOnClick: true
4716
4796
  }));
4717
4797
  }
@@ -6302,7 +6382,7 @@ var FilesView = Marionette.ItemView.extend({
6302
6382
  this.$el.append(this.subview(this.tabsView).el);
6303
6383
  },
6304
6384
  tab: function tab(fileType) {
6305
- var selectionMode = this.options.tabName === fileType.collectionName;
6385
+ var selectionMode = this.options.allowSelectingAny || this.options.tabName === fileType.collectionName;
6306
6386
  this.tabsView.tab(fileType.collectionName, _.bind(function () {
6307
6387
  return this.subview(new FilteredFilesView({
6308
6388
  entry: state.entry,
@@ -6488,10 +6568,10 @@ var PublishEntryView = Marionette.ItemView.extend({
6488
6568
  this.ui.publishUntilField.datepicker('setDate', publishedUntil);
6489
6569
  this.ui.publishUntilTimeField.val(timeStr(publishedUntil));
6490
6570
  } else {
6491
- this.ui.publishUntilField.datepicker('setDate', oneYearFromNow());
6571
+ this.ui.publishUntilField.datepicker('setDate', this.defaultPublishedUntilDate());
6492
6572
  }
6493
6573
 
6494
- this.ui.userNameField.val(state.account.get('name'));
6574
+ this.ui.userNameField.val(this.options.account.get('name'));
6495
6575
 
6496
6576
  if (this.model.get('password_protected')) {
6497
6577
  this.ui.passwordProtectedCheckBox.prop('checked', true);
@@ -6511,12 +6591,6 @@ var PublishEntryView = Marionette.ItemView.extend({
6511
6591
  return ("0" + val).slice(-2);
6512
6592
  }
6513
6593
  }
6514
-
6515
- function oneYearFromNow() {
6516
- var date = new Date();
6517
- date.setFullYear(date.getFullYear() + 1);
6518
- return date;
6519
- }
6520
6594
  },
6521
6595
  save: function save() {
6522
6596
  var publishedUntil = null;
@@ -6591,6 +6665,11 @@ var PublishEntryView = Marionette.ItemView.extend({
6591
6665
  return false;
6592
6666
  }
6593
6667
  },
6668
+ defaultPublishedUntilDate: function defaultPublishedUntilDate() {
6669
+ var date = new Date();
6670
+ date.setMonth(date.getMonth() + this.options.config.defaultPublishedUntilDurationInMonths);
6671
+ return date;
6672
+ },
6594
6673
  enableSave: function enableSave() {
6595
6674
  this.ui.saveButton.removeAttr('disabled');
6596
6675
  },
@@ -6690,10 +6769,16 @@ var SidebarController = Marionette.Controller.extend({
6690
6769
  }));
6691
6770
  },
6692
6771
  files: function files(collectionName, handler, payload, filterName) {
6772
+ var _split = (collectionName || '').split(':'),
6773
+ _split2 = _slicedToArray(_split, 2),
6774
+ tabName = _split2[0],
6775
+ suffix = _split2[1];
6776
+
6693
6777
  this.region.show(new FilesView({
6694
6778
  model: this.entry,
6695
6779
  selectionHandler: handler && editor.createFileSelectionHandler(handler, payload),
6696
- tabName: collectionName,
6780
+ tabName: tabName,
6781
+ allowSelectingAny: suffix === 'default',
6697
6782
  filterName: filterName
6698
6783
  }));
6699
6784
  editor.setDefaultHelpEntry('pageflow.help_entries.files');
@@ -6720,7 +6805,9 @@ var SidebarController = Marionette.Controller.extend({
6720
6805
  publish: function publish() {
6721
6806
  this.region.show(PublishEntryView.create({
6722
6807
  model: this.entry,
6723
- entryPublication: new EntryPublication()
6808
+ account: state.account,
6809
+ entryPublication: new EntryPublication(),
6810
+ config: state.config
6724
6811
  }));
6725
6812
  editor.setDefaultHelpEntry('pageflow.help_entries.publish');
6726
6813
  },
@@ -7090,7 +7177,15 @@ var HelpImageView = Marionette.View.extend({
7090
7177
 
7091
7178
  var InfoBoxView = Marionette.View.extend({
7092
7179
  className: 'info_box',
7180
+ mixins: [attributeBinding],
7181
+ initialize: function initialize() {
7182
+ this.setupBooleanAttributeBinding('visible', this.updateVisible);
7183
+ },
7184
+ updateVisible: function updateVisible() {
7185
+ this.$el.toggleClass('hidden_via_binding', this.getBooleanAttributBoundOption('visible') === false);
7186
+ },
7093
7187
  render: function render() {
7188
+ this.$el.addClass(this.options.level);
7094
7189
  this.$el.html(this.options.text);
7095
7190
  return this;
7096
7191
  }
@@ -8006,6 +8101,10 @@ app.addInitializer(function () {
8006
8101
  });
8007
8102
  });
8008
8103
 
8104
+ var OtherFile = UploadableFile.extend({
8105
+ thumbnailPictogram: 'other'
8106
+ });
8107
+
8009
8108
  app.addInitializer(function (options) {
8010
8109
  var textTracksMetaDataAttribute = {
8011
8110
  name: 'text_tracks',
@@ -8115,6 +8214,18 @@ app.addInitializer(function (options) {
8115
8214
  binding: 'label'
8116
8215
  }
8117
8216
  });
8217
+ editor.fileTypes.register('other_files', {
8218
+ model: OtherFile,
8219
+ metaDataAttributes: [altMetaDataAttribute],
8220
+ matchUpload: function matchUpload() {
8221
+ return true;
8222
+ },
8223
+ priority: 100,
8224
+ configurationEditorInputs: [{
8225
+ name: 'alt',
8226
+ inputView: TextInputView
8227
+ }]
8228
+ });
8118
8229
  editor.fileTypes.setup(options.config.fileTypes);
8119
8230
  });
8120
8231