pageflow 12.0.4 → 12.1.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 (217) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +158 -374
  3. data/README.md +24 -3
  4. data/Rakefile +2 -2
  5. data/admins/pageflow/accounts.rb +30 -4
  6. data/admins/pageflow/entry.rb +59 -9
  7. data/admins/pageflow/membership.rb +57 -6
  8. data/admins/pageflow/user.rb +25 -4
  9. data/app/assets/images/pageflow/themes/default/preview.png +0 -0
  10. data/app/assets/images/pageflow/themes/default/preview_thumbnail.png +0 -0
  11. data/app/assets/javascripts/pageflow/admin/entries.js +5 -3
  12. data/app/assets/javascripts/pageflow/admin/users.js +33 -0
  13. data/app/assets/javascripts/pageflow/admin.js +4 -1
  14. data/app/assets/javascripts/pageflow/audio_context.js +28 -0
  15. data/app/assets/javascripts/pageflow/audio_player/get_media_element_method.js +5 -0
  16. data/app/assets/javascripts/pageflow/audio_player.js +2 -0
  17. data/app/assets/javascripts/pageflow/base.js +4 -22
  18. data/app/assets/javascripts/pageflow/dist/react.js +323 -242
  19. data/app/assets/javascripts/pageflow/editor/api/widget_type.js +23 -0
  20. data/app/assets/javascripts/pageflow/editor/api/widget_types.js +53 -0
  21. data/app/assets/javascripts/pageflow/editor/api.js +9 -1
  22. data/app/assets/javascripts/pageflow/editor/base.js +0 -1
  23. data/app/assets/javascripts/pageflow/editor/collections/pages_collection.js +1 -0
  24. data/app/assets/javascripts/pageflow/editor/collections/subset_collection.js +21 -1
  25. data/app/assets/javascripts/pageflow/editor/collections/themes_collection.js +13 -0
  26. data/app/assets/javascripts/pageflow/editor/collections/widgets_collection.js +23 -8
  27. data/app/assets/javascripts/pageflow/editor/controllers/sidebar_controller.js +7 -1
  28. data/app/assets/javascripts/pageflow/editor/initializers/setup_collections.js +10 -3
  29. data/app/assets/javascripts/pageflow/editor/initializers/setup_widget_types.js +5 -1
  30. data/app/assets/javascripts/pageflow/editor/initializers/stylesheet_reloading.js +8 -3
  31. data/app/assets/javascripts/pageflow/editor/models/edit_lock_container.js +1 -1
  32. data/app/assets/javascripts/pageflow/editor/models/entry.js +7 -4
  33. data/app/assets/javascripts/pageflow/editor/models/entry_configuration.js +1 -1
  34. data/app/assets/javascripts/pageflow/editor/models/file_stage.js +1 -0
  35. data/app/assets/javascripts/pageflow/editor/models/page.js +3 -1
  36. data/app/assets/javascripts/pageflow/editor/models/preview_entry_data.js +2 -2
  37. data/app/assets/javascripts/pageflow/editor/models/theme.js +25 -0
  38. data/app/assets/javascripts/pageflow/editor/models/theming.js +1 -19
  39. data/app/assets/javascripts/pageflow/editor/models/widget.js +22 -1
  40. data/app/assets/javascripts/pageflow/editor/models/widget_configuration.js +5 -0
  41. data/app/assets/javascripts/pageflow/editor/routers/sidebar_router.js +1 -0
  42. data/app/assets/javascripts/pageflow/editor/templates/change_theme_dialog.jst.ejs +23 -0
  43. data/app/assets/javascripts/pageflow/editor/templates/edit_widget.jst.ejs +1 -2
  44. data/app/assets/javascripts/pageflow/editor/templates/inputs/reference.jst.ejs +2 -2
  45. data/app/assets/javascripts/pageflow/editor/templates/static_thumbnail.jst.ejs +1 -0
  46. data/app/assets/javascripts/pageflow/editor/templates/theme_item.jst.ejs +5 -0
  47. data/app/assets/javascripts/pageflow/editor/templates/widget_item.jst.ejs +3 -0
  48. data/app/assets/javascripts/pageflow/editor/utils/stylesheet.js +23 -0
  49. data/app/assets/javascripts/pageflow/editor/views/change_theme_dialog_view.js +76 -0
  50. data/app/assets/javascripts/pageflow/editor/views/configuration_editors/groups/options.js +4 -2
  51. data/app/assets/javascripts/pageflow/editor/views/edit_meta_data_view.js +17 -4
  52. data/app/assets/javascripts/pageflow/editor/views/edit_widget_view.js +11 -21
  53. data/app/assets/javascripts/pageflow/editor/views/edit_widgets_view.js +1 -3
  54. data/app/assets/javascripts/pageflow/editor/views/file_meta_data_item_value_view.js +10 -1
  55. data/app/assets/javascripts/pageflow/editor/views/inputs/reference_input_view.js +36 -4
  56. data/app/assets/javascripts/pageflow/editor/views/inputs/theme_input_view.js +26 -0
  57. data/app/assets/javascripts/pageflow/editor/views/model_thumbnail_view.js +28 -14
  58. data/app/assets/javascripts/pageflow/editor/views/static_thumbnail_view.js +20 -0
  59. data/app/assets/javascripts/pageflow/editor/views/theme_item_view.js +41 -0
  60. data/app/assets/javascripts/pageflow/editor/views/widget_item_view.js +49 -0
  61. data/app/assets/javascripts/pageflow/history.js +7 -1
  62. data/app/assets/javascripts/pageflow/media_player/volume_fading/interval.js +65 -0
  63. data/app/assets/javascripts/pageflow/media_player/volume_fading/noop.js +5 -0
  64. data/app/assets/javascripts/pageflow/media_player/volume_fading/web_audio.js +109 -0
  65. data/app/assets/javascripts/pageflow/media_player/volume_fading.js +14 -65
  66. data/app/assets/javascripts/pageflow/slideshow/dom_order_scroll_navigator.js +5 -2
  67. data/app/assets/javascripts/pageflow/slideshow.js +19 -8
  68. data/app/assets/javascripts/pageflow/ui/views/configuration_editor_view.js +4 -0
  69. data/app/assets/javascripts/pageflow/ui/views/inputs/text_area_input_view.js +10 -5
  70. data/app/assets/javascripts/pageflow/ui/views/inputs/text_input_view.js +4 -48
  71. data/app/assets/javascripts/pageflow/ui/views/mixins/input_with_placeholder_text.js +58 -0
  72. data/app/assets/javascripts/pageflow/vendor.js +16 -0
  73. data/app/assets/javascripts/pageflow/video_player/get_media_element_method.js +6 -0
  74. data/app/assets/javascripts/pageflow/video_player.js +2 -0
  75. data/app/assets/stylesheets/pageflow/admin/entries.scss +1 -1
  76. data/app/assets/stylesheets/pageflow/admin/quotas.scss +1 -1
  77. data/app/assets/stylesheets/pageflow/admin.scss +2 -0
  78. data/app/assets/stylesheets/pageflow/base.scss +0 -1
  79. data/app/assets/stylesheets/pageflow/editor/base.scss +2 -0
  80. data/app/assets/stylesheets/pageflow/editor/change_theme.scss +114 -0
  81. data/app/assets/stylesheets/pageflow/editor/static_thumbnails.scss +4 -0
  82. data/app/assets/stylesheets/pageflow/editor/widgets.scss +26 -2
  83. data/app/assets/stylesheets/pageflow/page.scss +1 -14
  84. data/app/assets/stylesheets/pageflow/themes/default/indicators.scss +12 -0
  85. data/app/assets/stylesheets/pageflow/themes/default/loading_spinner.scss +11 -0
  86. data/app/assets/stylesheets/pageflow/themes/default/logo/alignment.scss +27 -0
  87. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/background_image.scss +20 -2
  88. data/app/assets/stylesheets/pageflow/themes/default/logo/variant/watermark.scss +4 -1
  89. data/app/assets/stylesheets/pageflow/themes/default/page/line_lengths.scss +113 -0
  90. data/app/assets/stylesheets/pageflow/themes/default/page.scss +1 -0
  91. data/app/controllers/pageflow/editor/widgets_controller.rb +15 -1
  92. data/app/controllers/pageflow/entries_controller.rb +1 -1
  93. data/app/helpers/pageflow/admin/entries_helper.rb +0 -9
  94. data/app/helpers/pageflow/admin/memberships_helper.rb +43 -123
  95. data/app/helpers/pageflow/admin/users_helper.rb +15 -0
  96. data/app/helpers/pageflow/entries_helper.rb +3 -1
  97. data/app/helpers/pageflow/entry_json_seed_helper.rb +9 -3
  98. data/app/helpers/pageflow/public_i18n_helper.rb +2 -2
  99. data/app/helpers/pageflow/quota_helper.rb +2 -2
  100. data/app/helpers/pageflow/social_share_helper.rb +3 -2
  101. data/app/helpers/pageflow/themes_helper.rb +11 -3
  102. data/app/helpers/pageflow/widgets_helper.rb +10 -2
  103. data/app/jobs/pageflow/prune_auto_snapshots_job.rb +9 -0
  104. data/app/mailers/pageflow/user_mailer.rb +11 -1
  105. data/app/models/concerns/pageflow/feature_target.rb +1 -1
  106. data/app/models/concerns/pageflow/hosted_file.rb +9 -0
  107. data/app/models/concerns/pageflow/output_source.rb +2 -1
  108. data/app/models/concerns/pageflow/serialization_blacklist.rb +19 -0
  109. data/app/models/concerns/pageflow/serialized_configuration.rb +17 -0
  110. data/app/models/concerns/pageflow/theme_referencer.rb +23 -0
  111. data/app/models/pageflow/account.rb +6 -1
  112. data/app/models/pageflow/account_member_query.rb +6 -12
  113. data/app/models/pageflow/account_role_query.rb +68 -0
  114. data/app/models/pageflow/application_query.rb +13 -0
  115. data/app/models/pageflow/application_record.rb +5 -0
  116. data/app/models/pageflow/audio_file.rb +1 -1
  117. data/app/models/pageflow/auto_snapshot_pruning.rb +26 -0
  118. data/app/models/pageflow/chapter.rb +4 -8
  119. data/app/models/pageflow/draft_entry.rb +2 -1
  120. data/app/models/pageflow/edit_lock.rb +11 -5
  121. data/app/models/pageflow/encoding_confirmation.rb +2 -1
  122. data/app/models/pageflow/entry.rb +13 -2
  123. data/app/models/pageflow/entry_publication.rb +2 -0
  124. data/app/models/pageflow/entry_role_query.rb +24 -9
  125. data/app/models/pageflow/entry_title_or_account_name_query.rb +33 -0
  126. data/app/models/pageflow/file_usage.rb +3 -7
  127. data/app/models/pageflow/folder.rb +1 -1
  128. data/app/models/pageflow/home_button.rb +1 -1
  129. data/app/models/pageflow/image_file.rb +22 -4
  130. data/app/models/pageflow/invitation_form.rb +10 -4
  131. data/app/models/pageflow/managed_user_query.rb +44 -0
  132. data/app/models/pageflow/membership.rb +1 -1
  133. data/app/models/pageflow/overview_button.rb +3 -4
  134. data/app/models/pageflow/page.rb +3 -7
  135. data/app/models/pageflow/potential_memberships.rb +112 -0
  136. data/app/models/pageflow/published_entry.rb +2 -1
  137. data/app/models/pageflow/revision.rb +13 -4
  138. data/app/models/pageflow/storyline.rb +3 -4
  139. data/app/models/pageflow/text_track_file.rb +1 -1
  140. data/app/models/pageflow/theming.rb +15 -10
  141. data/app/models/pageflow/url_template.rb +8 -2
  142. data/app/models/pageflow/user_name_query.rb +30 -0
  143. data/app/models/pageflow/video_file.rb +5 -1
  144. data/app/models/pageflow/widget.rb +3 -1
  145. data/app/models/pageflow/zencoder_attachment.rb +16 -5
  146. data/app/policies/pageflow/account_policy.rb +31 -61
  147. data/app/policies/pageflow/application_policy.rb +6 -0
  148. data/app/policies/pageflow/entry_policy.rb +11 -3
  149. data/app/policies/pageflow/membership_policy.rb +1 -2
  150. data/app/policies/pageflow/user_policy.rb +20 -1
  151. data/app/views/admin/accounts/_form.html.erb +4 -4
  152. data/app/views/admin/accounts/_theming_defaults_inline_help.html.erb +5 -0
  153. data/app/views/admin/memberships/_form.html.erb +9 -14
  154. data/app/views/admin/memberships/_role_hint.html.arb +1 -1
  155. data/app/views/admin/users/invitation.html.erb +18 -9
  156. data/app/views/admin/users/me.html.erb +2 -2
  157. data/app/views/admin/users/quota_state.html.erb +1 -0
  158. data/app/views/components/pageflow/admin/add_membership_button.rb +81 -0
  159. data/app/views/components/pageflow/admin/members_tab.rb +6 -4
  160. data/app/views/components/pageflow/admin/revisions_tab.rb +16 -4
  161. data/app/views/components/pageflow/admin/user_accounts_tab.rb +8 -2
  162. data/app/views/components/pageflow/admin/user_entries_tab.rb +6 -2
  163. data/app/views/components/pageflow/admin/users_tab.rb +9 -5
  164. data/app/views/layouts/pageflow/application.html.erb +2 -1
  165. data/app/views/pageflow/admin/users/_quota_exhausted.html.erb +1 -0
  166. data/app/views/pageflow/admin/users/_quota_state.html.erb +7 -0
  167. data/app/views/pageflow/config/_editor_seeds.json.jbuilder +2 -0
  168. data/app/views/pageflow/editor/entries/_entry.json.jbuilder +1 -0
  169. data/app/views/pageflow/editor/entries/seed.json.erb +3 -1
  170. data/app/views/pageflow/editor/image_files/_image_file.json.jbuilder +1 -1
  171. data/app/views/pageflow/editor/themings/_theming.json.jbuilder +0 -7
  172. data/app/views/pageflow/editor/widgets/_widget.json.jbuilder +1 -1
  173. data/app/views/pageflow/entries/_entry.html.erb +5 -5
  174. data/app/views/pageflow/entries/edit.html.erb +1 -1
  175. data/app/views/pageflow/entries/show.html.erb +1 -1
  176. data/app/views/pageflow/entry_json_seed/_entry.json.jbuilder +1 -0
  177. data/app/views/pageflow/themes/_theme.json.jbuilder +13 -0
  178. data/config/initializers/admin_resource_tabs.rb +19 -6
  179. data/config/initializers/features.rb +1 -0
  180. data/config/locales/de.yml +26 -3
  181. data/config/locales/en.yml +26 -3
  182. data/db/migrate/20170201074328_add_configuration_to_widgets.rb +5 -0
  183. data/db/migrate/20170222124848_update_video_file_output_presences.rb +1 -1
  184. data/db/migrate/20170315130000_add_theme_name_to_revisions.rb +12 -0
  185. data/db/migrate/20170912165050_reset_copied_snapshot_type.rb +24 -0
  186. data/lib/generators/pageflow/routes/routes_generator.rb +11 -1
  187. data/lib/generators/pageflow/seeds/seeds_generator.rb +5 -0
  188. data/lib/generators/pageflow/seeds/templates/seeds.rb +5 -3
  189. data/lib/generators/pageflow/theme/templates/preview.png +0 -0
  190. data/lib/generators/pageflow/theme/templates/preview_thumbnail.png +0 -0
  191. data/lib/generators/pageflow/theme/theme_generator.rb +3 -0
  192. data/lib/pageflow/ability_mixin.rb +27 -6
  193. data/lib/pageflow/active_admin_can_can_fix.rb +34 -0
  194. data/lib/pageflow/configuration/permissions.rb +27 -0
  195. data/lib/pageflow/configuration.rb +28 -0
  196. data/lib/pageflow/engine.rb +25 -19
  197. data/lib/pageflow/images/palette.png +0 -0
  198. data/lib/pageflow/seeds.rb +1 -1
  199. data/lib/pageflow/theme.rb +8 -0
  200. data/lib/pageflow/version.rb +1 -1
  201. data/lib/pageflow/widget_type.rb +13 -0
  202. data/lib/pageflow/zencoder_video_output_definition.rb +16 -16
  203. data/lib/tasks/pageflow_tasks.rake +14 -0
  204. data/spec/factories/entries.rb +4 -0
  205. data/spec/factories/revisions.rb +10 -0
  206. data/spec/factories/users.rb +6 -0
  207. data/spec/factories/video_files.rb +4 -0
  208. data/vendor/assets/javascripts/audio5.min.js +3 -0
  209. metadata +78 -15
  210. data/app/assets/javascripts/pageflow/editor/models/mixins/widget_subject.js +0 -37
  211. data/app/assets/javascripts/pageflow/editor/utils/reload_stylesheet.js +0 -9
  212. data/app/assets/stylesheets/pageflow/text_variants.scss +0 -24
  213. data/app/views/admin/accounts/_widgets_inline_help.html.erb +0 -5
  214. data/app/views/admin/memberships/_entity_account_input.html.erb +0 -5
  215. data/app/views/admin/memberships/_entity_entry_input.html.erb +0 -5
  216. data/app/views/admin/users/_quota_exhausted.html.erb +0 -1
  217. data/app/views/components/pageflow/admin/add_membership_button_if_needed.rb +0 -62
@@ -24,7 +24,7 @@ pageflow.EditMetaDataView = Backbone.Marionette.Layout.extend({
24
24
 
25
25
  configurationEditor.tab('general', function() {
26
26
  this.input('title', pageflow.TextInputView, {
27
- placeholder: entry.attributes.entry_title
27
+ placeholder: entry.get('entry_title')
28
28
  });
29
29
  this.input('locale', pageflow.SelectInputView, {
30
30
  values: pageflow.config.availablePublicLocales,
@@ -47,18 +47,20 @@ pageflow.EditMetaDataView = Backbone.Marionette.Layout.extend({
47
47
  });
48
48
 
49
49
  configurationEditor.tab('widgets', function() {
50
+ var theme = entry.getTheme();
51
+
50
52
  this.input('manual_start', pageflow.CheckBoxInputView);
51
53
  this.input('emphasize_chapter_beginning', pageflow.CheckBoxInputView);
52
54
  this.input('emphasize_new_pages', pageflow.CheckBoxInputView);
53
55
  this.input('home_button_enabled', pageflow.CheckBoxInputView, {
54
- disabled: !pageflow.theming.hasHomeButton(),
56
+ disabled: !theme.hasHomeButton(),
55
57
  displayUncheckedIfDisabled: true
56
58
  });
57
59
  this.input('overview_button_enabled', pageflow.CheckBoxInputView, {
58
- disabled: !pageflow.theming.hasOverviewButton(),
60
+ disabled: !theme.hasOverviewButton(),
59
61
  displayUncheckedIfDisabled: true
60
62
  });
61
- if (pageflow.theming.hasHomeButton()) {
63
+ if (theme.hasHomeButton()) {
62
64
  this.input('home_url', pageflow.TextInputView, {
63
65
  placeholder: pageflow.theming.get('pretty_url'),
64
66
  visibleBinding: 'home_button_enabled'
@@ -68,6 +70,13 @@ pageflow.EditMetaDataView = Backbone.Marionette.Layout.extend({
68
70
  model: entry,
69
71
  widgetTypes: pageflow.editor.widgetTypes
70
72
  });
73
+ if (pageflow.features.isEnabled('selectable_themes') &&
74
+ pageflow.themes.length > 1) {
75
+ this.view(pageflow.ThemeInputView, {
76
+ themes: pageflow.themes,
77
+ propertyName: 'theme_name'
78
+ });
79
+ }
71
80
  });
72
81
 
73
82
  configurationEditor.tab('social', function() {
@@ -84,6 +93,10 @@ pageflow.EditMetaDataView = Backbone.Marionette.Layout.extend({
84
93
  });
85
94
  });
86
95
 
96
+ this.listenTo(entry.configuration, 'change:theme_name', function() {
97
+ configurationEditor.refresh();
98
+ });
99
+
87
100
  this.formContainer.show(configurationEditor);
88
101
  },
89
102
 
@@ -1,29 +1,19 @@
1
- pageflow.EditWidgetView = Backbone.Marionette.Layout.extend({
1
+ pageflow.EditWidgetView = Backbone.Marionette.ItemView.extend({
2
2
  template: 'templates/edit_widget',
3
- tagName: 'li',
4
3
  className: 'edit_widget',
5
4
 
6
- regions: {
7
- widgetTypeContainer: '.widget_type'
8
- },
9
-
10
- ui: {
11
- role: 'h2'
5
+ events: {
6
+ 'click a.back': function() {
7
+ editor.navigate('/meta_data/widgets', {trigger: true});
8
+ }
12
9
  },
13
10
 
14
11
  onRender: function() {
15
- var widgetTypes = this.options.widgetTypes[this.model.role()] || [];
16
-
17
- this.widgetTypeContainer.show(new pageflow.SelectInputView({
18
- model: this.model,
19
- propertyName: 'type_name',
20
- label: I18n.t('pageflow.widgets.roles.' + this.model.role()),
21
- collection: widgetTypes,
22
- valueProperty: 'name',
23
- translationKeyProperty: 'translationKey',
24
- includeBlank: true
25
- }));
12
+ var configurationEditor = this.model.widgetType().createConfigurationEditorView({
13
+ model: this.model.configuration,
14
+ tab: this.options.tab
15
+ });
26
16
 
27
- this.$el.toggle(widgetTypes.length > 1);
17
+ this.appendSubview(configurationEditor);
28
18
  }
29
- });
19
+ });
@@ -9,12 +9,10 @@ pageflow.EditWidgetsView = Backbone.Marionette.Layout.extend({
9
9
  this.subview(new pageflow.CollectionView({
10
10
  el: this.ui.widgets,
11
11
  collection: this.model.widgets,
12
- itemViewConstructor: pageflow.EditWidgetView,
12
+ itemViewConstructor: pageflow.WidgetItemView,
13
13
  itemViewOptions: {
14
14
  widgetTypes: this.options.widgetTypes
15
15
  }
16
16
  }).render());
17
-
18
- this.model.fetchWidgets();
19
17
  }
20
18
  });
@@ -31,9 +31,13 @@ pageflow.FileMetaDataItemValueView = Backbone.Marionette.ItemView.extend({
31
31
  }
32
32
  },
33
33
 
34
+ modelEvents: {
35
+ 'change': 'toggleEditLink'
36
+ },
37
+
34
38
  onRender: function() {
35
39
  this.listenTo(this.model, 'change:' + this.options.name, this.update);
36
- this.ui.editLink.toggle(!!this.options.settingsDialogTabLink);
40
+ this.toggleEditLink();
37
41
 
38
42
  this.update();
39
43
  },
@@ -45,5 +49,10 @@ pageflow.FileMetaDataItemValueView = Backbone.Marionette.ItemView.extend({
45
49
 
46
50
  getText: function() {
47
51
  throw new Error('Not implemented');
52
+ },
53
+
54
+ toggleEditLink: function() {
55
+ this.ui.editLink.toggle(!!this.options.settingsDialogTabLink &&
56
+ !this.model.isNew());
48
57
  }
49
58
  });
@@ -14,6 +14,7 @@ pageflow.ReferenceInputView = Backbone.Marionette.ItemView.extend(
14
14
 
15
15
  ui: {
16
16
  title: '.title',
17
+ chooseButton: '.choose',
17
18
  unsetButton: '.unset',
18
19
  buttons: 'button'
19
20
  },
@@ -22,8 +23,8 @@ pageflow.ReferenceInputView = Backbone.Marionette.ItemView.extend(
22
23
  'click .choose': function() {
23
24
  var view = this;
24
25
 
25
- this.choose().then(function(site) {
26
- view.model.set(view.options.propertyName, site.get('perma_id'));
26
+ this.chooseValue().then(function(id) {
27
+ view.model.set(view.options.propertyName, id);
27
28
  });
28
29
 
29
30
  return false;
@@ -44,11 +45,26 @@ pageflow.ReferenceInputView = Backbone.Marionette.ItemView.extend(
44
45
  this.listenTo(this.model, 'change:' + this.options.propertyName, this.update);
45
46
  },
46
47
 
48
+ /**
49
+ * Returns a promise for some identifying attribute.
50
+ *
51
+ * Default attribute name is perma_id. If the attribute is named
52
+ * differently, you can have your specific ReferenceInputView
53
+ * implement `chooseValue()` accordingly.
54
+ *
55
+ * Will be used to set the chosen Model for this View.
56
+ */
57
+ chooseValue: function() {
58
+ return this.choose().then(function(model) {
59
+ return model.get('perma_id');
60
+ });
61
+ },
62
+
47
63
  choose: function() {
48
64
  throw 'Not implemented: Override ReferenceInputView#choose to return a promise';
49
65
  },
50
66
 
51
- getTarget: function() {
67
+ getTarget: function(targetId) {
52
68
  throw 'Not implemented: Override ReferenceInputView#getTarget';
53
69
  },
54
70
 
@@ -59,10 +75,26 @@ pageflow.ReferenceInputView = Backbone.Marionette.ItemView.extend(
59
75
  },
60
76
 
61
77
  update: function() {
78
+ if (this.isClosed) {
79
+ return;
80
+ }
81
+
62
82
  var target = this.getTarget(this.model.get(this.options.propertyName));
63
83
 
64
84
  this.ui.title.text(target ? target.title() : I18n.t('pageflow.editor.views.inputs.reference_input_view.none'));
65
- this.ui.unsetButton.toggle(!!target);
85
+
86
+ this.ui.unsetButton.toggle(!!target && !this.options.hideUnsetButton);
87
+ this.ui.unsetButton.attr(
88
+ 'title',
89
+ this.options.unsetButtonTitle ||
90
+ I18n.t('pageflow.editor.views.inputs.reference_input_view.unset')
91
+ );
92
+
93
+ this.ui.chooseButton.attr(
94
+ 'title',
95
+ this.options.chooseButtonTitle ||
96
+ I18n.t('pageflow.editor.views.inputs.reference_input_view.choose')
97
+ );
66
98
 
67
99
  this.updateDisabledAttribute(this.ui.buttons);
68
100
 
@@ -0,0 +1,26 @@
1
+ pageflow.ThemeInputView = pageflow.ReferenceInputView.extend({
2
+ options: function() {
3
+ return {
4
+ chooseButtonTitle: I18n.t('pageflow.editor.views.inputs.theme_input_view.choose'),
5
+ hideUnsetButton: true
6
+ };
7
+ },
8
+
9
+ choose: function() {
10
+ return pageflow.ChangeThemeDialogView.changeTheme({
11
+ model: this.model,
12
+ themes: this.options.themes,
13
+ themeInUse: this.model.get(this.options.propertyName)
14
+ });
15
+ },
16
+
17
+ chooseValue: function() {
18
+ return this.choose().then(function(model) {
19
+ return model.get('name');
20
+ });
21
+ },
22
+
23
+ getTarget: function(themeName) {
24
+ return this.options.themes.findByName(themeName);
25
+ }
26
+ });
@@ -17,24 +17,38 @@ pageflow.ModelThumbnailView = Backbone.Marionette.View.extend({
17
17
  },
18
18
 
19
19
  update: function() {
20
- var file = this.model && this.model.thumbnailFile();
21
-
22
- if (this.fileThumbnailView && this.currentFileThumbnail == file) {
23
- return;
20
+ if (this.model) {
21
+ if (_.isFunction(this.model.thumbnailFile)) {
22
+ var file = this.model && this.model.thumbnailFile();
23
+
24
+ if (this.thumbnailView && this.currentFileThumbnail == file) {
25
+ return;
26
+ }
27
+
28
+ this.currentFileThumbnail = file;
29
+
30
+ this.newThumbnailView = new pageflow.FileThumbnailView({
31
+ model: file,
32
+ className: 'thumbnail file_thumbnail',
33
+ imageUrlPropertyName: this.options.imageUrlPropertyName
34
+ });
35
+ }
36
+ else {
37
+ this.newThumbnailView = this.newThumbnailView ||
38
+ new pageflow.StaticThumbnailView({
39
+ model: this.model
40
+ });
41
+ }
24
42
  }
25
43
 
26
- this.currentFileThumbnail = file;
27
-
28
- if (this.fileThumbnailView) {
29
- this.fileThumbnailView.close();
44
+ if (this.thumbnailView) {
45
+ this.thumbnailView.close();
30
46
  }
31
47
 
32
- this.fileThumbnailView = this.subview(new pageflow.FileThumbnailView({
33
- model: file,
34
- className: 'thumbnail file_thumbnail',
35
- imageUrlPropertyName: this.options.imageUrlPropertyName
36
- }));
48
+ if (this.model) {
49
+ this.thumbnailView = this.subview(this.newThumbnailView);
37
50
 
38
- this.$el.append(this.fileThumbnailView.el);
51
+ this.$el.append(this.thumbnailView.el);
52
+ }
39
53
  }
40
54
  });
@@ -0,0 +1,20 @@
1
+ pageflow.StaticThumbnailView = Backbone.Marionette.ItemView.extend({
2
+ template: 'templates/static_thumbnail',
3
+ className: 'static_thumbnail',
4
+
5
+ modelEvents: {
6
+ 'change:configuration': 'update'
7
+ },
8
+
9
+ onRender: function() {
10
+ this.update();
11
+ },
12
+
13
+ update: function() {
14
+ this.$el.css('background-image', 'url(' + this._imageUrl() + ')');
15
+ },
16
+
17
+ _imageUrl: function() {
18
+ return this.model.thumbnailUrl();
19
+ }
20
+ });
@@ -0,0 +1,41 @@
1
+ /** @api private */
2
+ pageflow.ThemeItemView = Backbone.Marionette.ItemView.extend({
3
+ tagName: 'li',
4
+ template: 'pageflow/editor/templates/theme_item',
5
+ className: 'theme_item',
6
+
7
+ mixins: [pageflow.selectableView],
8
+
9
+ selectionAttribute: 'theme',
10
+
11
+ ui: {
12
+ themeName: '.theme_name',
13
+ useButton: '.use_theme',
14
+ inUseRegion: '.theme_in_use'
15
+ },
16
+
17
+ events: {
18
+ 'click .use_theme': function() {
19
+ this.options.onUse(this.model);
20
+ },
21
+ 'mouseenter': 'select',
22
+ 'click': 'select'
23
+ },
24
+
25
+ onRender: function() {
26
+ this.$el.data('themeName', this.model.get('name'));
27
+ this.ui.themeName.text(this.model.title());
28
+
29
+ if (this.inUse()) {
30
+ this.ui.inUseRegion.text('✓');
31
+ }
32
+
33
+ this.ui.useButton.toggle(
34
+ !this.inUse()
35
+ );
36
+ },
37
+
38
+ inUse: function() {
39
+ return this.model.get('name') === this.options.themeInUse;
40
+ }
41
+ });
@@ -0,0 +1,49 @@
1
+ pageflow.WidgetItemView = Backbone.Marionette.Layout.extend({
2
+ template: 'templates/widget_item',
3
+ tagName: 'li',
4
+ className: 'widget_item',
5
+
6
+ regions: {
7
+ widgetTypeContainer: '.widget_type'
8
+ },
9
+
10
+ ui: {
11
+ role: 'h2'
12
+ },
13
+
14
+ modelEvents: {
15
+ 'change:type_name': 'update'
16
+ },
17
+
18
+ events: {
19
+ 'click .settings': function() {
20
+ pageflow.editor.navigate('/widgets/' + this.model.role(), {trigger: true});
21
+ return false;
22
+ },
23
+ },
24
+
25
+ onRender: function() {
26
+ var widgetTypes = this.options.widgetTypes.findAllByRole(this.model.role()) || [];
27
+ var isOptional = this.options.widgetTypes.isOptional(this.model.role());
28
+
29
+ this.widgetTypeContainer.show(new pageflow.SelectInputView({
30
+ model: this.model,
31
+ propertyName: 'type_name',
32
+ label: I18n.t('pageflow.widgets.roles.' + this.model.role()),
33
+ collection: widgetTypes,
34
+ valueProperty: 'name',
35
+ translationKeyProperty: 'translationKey',
36
+ includeBlank: isOptional || !this.model.get('type_name')
37
+ }));
38
+
39
+ this.$el.toggleClass('is_hidden', widgetTypes.length <= 1 &&
40
+ !this.model.hasConfiguration() &&
41
+ !isOptional);
42
+
43
+ this.update();
44
+ },
45
+
46
+ update: function() {
47
+ this.$el.toggleClass('has_settings', this.model.hasConfiguration());
48
+ }
49
+ });
@@ -8,6 +8,9 @@ pageflow.History = function(slideshow, adapter) {
8
8
  if (options.back) {
9
9
  adapter.replaceState(null, '', adapter.hash());
10
10
  }
11
+ else if (options.ignoreInHistory) {
12
+ adapter.replaceState(null, '', hash);
13
+ }
11
14
  else {
12
15
  adapter.replaceState(options, '', adapter.hash());
13
16
  adapter.pushState(null, '', hash);
@@ -28,8 +31,11 @@ pageflow.History = function(slideshow, adapter) {
28
31
  slideshow.goToByPermaId(adapter.hash());
29
32
  });
30
33
 
34
+ this.getLandingPagePermaId = function() {
35
+ return adapter.hash() || pageParameter();
36
+ };
37
+
31
38
  this.start = function() {
32
- slideshow.goToByPermaId(adapter.hash() || pageParameter());
33
39
  adapter.replaceState(null, '', slideshow.currentPage().attr('id'));
34
40
  };
35
41
 
@@ -0,0 +1,65 @@
1
+ pageflow.mediaPlayer.volumeFading.interval = function(player) {
2
+ var originalVolume = player.volume;
3
+
4
+ var fadeVolumeDeferred;
5
+ var fadeVolumeInterval;
6
+
7
+ player.volume = function(value) {
8
+ if (typeof value !== 'undefined') {
9
+ cancelFadeVolume();
10
+ }
11
+
12
+ return originalVolume.apply(player, arguments);
13
+ };
14
+
15
+ player.fadeVolume = function(value, duration) {
16
+ cancelFadeVolume();
17
+
18
+ return new $.Deferred(function(deferred) {
19
+ var resolution = 10;
20
+ var startValue = volume();
21
+ var steps = duration / resolution;
22
+ var leap = (value - startValue) / steps;
23
+
24
+ if (value === startValue) {
25
+ deferred.resolve();
26
+ }
27
+ else {
28
+ fadeVolumeDeferred = deferred;
29
+ fadeVolumeInterval = setInterval(function() {
30
+ volume(volume() + leap);
31
+
32
+ if ((volume() >= value && value >= startValue) ||
33
+ (volume() <= value && value <= startValue)) {
34
+
35
+ resolveFadeVolume();
36
+ }
37
+ }, resolution);
38
+ }
39
+ });
40
+ };
41
+
42
+ player.one('dispose', cancelFadeVolume);
43
+
44
+ function volume(/* arguments */) {
45
+ return originalVolume.apply(player, arguments);
46
+ }
47
+
48
+ function resolveFadeVolume() {
49
+ clearInterval(fadeVolumeInterval);
50
+ fadeVolumeDeferred.resolve();
51
+
52
+ fadeVolumeInterval = null;
53
+ fadeVolumeDeferred = null;
54
+ }
55
+
56
+ function cancelFadeVolume() {
57
+ if (fadeVolumeInterval) {
58
+ clearInterval(fadeVolumeInterval);
59
+ fadeVolumeDeferred.reject();
60
+
61
+ fadeVolumeInterval = null;
62
+ fadeVolumeDeferred = null;
63
+ }
64
+ }
65
+ };
@@ -0,0 +1,5 @@
1
+ pageflow.mediaPlayer.volumeFading.noop = function(player) {
2
+ player.fadeVolume = function(value, duration) {
3
+ return new jQuery.Deferred().resolve().promise();
4
+ };
5
+ };
@@ -0,0 +1,109 @@
1
+ pageflow.mediaPlayer.volumeFading.webAudio = function(player, audioContext) {
2
+ var gainNode;
3
+
4
+ var currentDeferred;
5
+ var currentTimeout;
6
+
7
+ var currentValue = 1;
8
+
9
+ var lastStartTime;
10
+ var lastDuration;
11
+ var lastStartValue;
12
+
13
+ var allowedMinValue = 0.000001;
14
+
15
+ player.volume = function(value) {
16
+ ensureGainNode();
17
+
18
+ if (typeof value !== 'undefined') {
19
+ cancel();
20
+ currentValue = ensureInAllowedRange(value);
21
+
22
+ return gainNode.gain.setValueAtTime(currentValue,
23
+ audioContext.currentTime);
24
+ }
25
+
26
+ return Math.round(currentValue * 100) / 100;
27
+ };
28
+
29
+ player.fadeVolume = function(value, duration) {
30
+ ensureGainNode();
31
+
32
+ cancel();
33
+ recordFadeStart(duration);
34
+
35
+ currentValue = ensureInAllowedRange(value);
36
+
37
+ gainNode.gain.setValueAtTime(lastStartValue, audioContext.currentTime);
38
+ gainNode.gain.linearRampToValueAtTime(currentValue,
39
+ audioContext.currentTime + duration / 1000);
40
+
41
+ return new $.Deferred(function(deferred) {
42
+ currentTimeout = setTimeout(resolve, duration);
43
+ currentDeferred = deferred;
44
+ }).promise();
45
+ };
46
+
47
+ player.one('dispose', cancel);
48
+
49
+ function ensureGainNode() {
50
+ if (!gainNode) {
51
+ gainNode = audioContext.createGain();
52
+
53
+ var source = audioContext.createMediaElementSource(player.getMediaElement());
54
+
55
+ source.connect(gainNode);
56
+ gainNode.connect(audioContext.destination);
57
+ }
58
+ }
59
+
60
+ function resolve() {
61
+ clearTimeout(currentTimeout);
62
+ currentDeferred.resolve();
63
+
64
+ currentTimeout = null;
65
+ currentDeferred = null;
66
+ }
67
+
68
+ function cancel() {
69
+ if (currentDeferred) {
70
+ gainNode.gain.cancelScheduledValues(audioContext.currentTime);
71
+
72
+ clearTimeout(currentTimeout);
73
+ currentDeferred.reject();
74
+
75
+ currentTimeout = null;
76
+ currentDeferred = null;
77
+
78
+ updateCurrentValueFromComputedValue();
79
+ }
80
+ }
81
+
82
+ function recordFadeStart(duration) {
83
+ lastStartTime = audioContext.currentTime;
84
+ lastStartValue = currentValue;
85
+ lastDuration = duration;
86
+ }
87
+
88
+ function updateCurrentValueFromComputedValue() {
89
+ // Firefox 54 on Ubuntu does not provide computed values when gain
90
+ // was changed via one of the scheduling methods. Instead
91
+ // gain.value always reports 1. Interpolate manually do determine
92
+ // how far the fade was performed before cancel was called.
93
+ if (gainNode.gain.value == 1) {
94
+ var performedDuration = (audioContext.currentTime - lastStartTime) * 1000;
95
+ var lastDelta = currentValue - lastStartValue;
96
+
97
+ currentValue = ensureInAllowedRange(
98
+ lastStartValue + (performedDuration / lastDuration * lastDelta)
99
+ );
100
+ }
101
+ else {
102
+ currentValue = gainNode.gain.value;
103
+ }
104
+ }
105
+
106
+ function ensureInAllowedRange(value) {
107
+ return value < allowedMinValue ? allowedMinValue : value;
108
+ }
109
+ };