pageflow 13.0.0.beta7 → 13.0.0.rc1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/Rakefile +1 -1
  4. data/admins/pageflow/entry.rb +1 -1
  5. data/admins/pageflow/revisions.rb +3 -4
  6. data/app/assets/javascripts/pageflow/admin/accounts.js +1 -1
  7. data/app/assets/javascripts/pageflow/background_media.js +1 -1
  8. data/app/assets/javascripts/pageflow/base.js +1 -1
  9. data/app/assets/javascripts/pageflow/dist/react.js +1166 -982
  10. data/app/assets/javascripts/pageflow/media_player/volume_binding.js +2 -1
  11. data/app/assets/javascripts/pageflow/media_player/volume_fading/web_audio.js +60 -37
  12. data/app/assets/javascripts/pageflow/slideshow.js +15 -8
  13. data/app/assets/javascripts/pageflow/slideshow/adjacent_pages.js +9 -4
  14. data/app/assets/javascripts/pageflow/slideshow/adjacent_preloader.js +26 -0
  15. data/app/assets/javascripts/pageflow/slideshow/lazy_page_widget.js +2 -2
  16. data/app/assets/javascripts/pageflow/slideshow/successor_preparer.js +49 -0
  17. data/app/assets/javascripts/pageflow/ui/views/inputs/text_input_view.js +29 -5
  18. data/app/assets/javascripts/pageflow/ui/views/mixins/input_view.js +1 -1
  19. data/app/assets/javascripts/pageflow/widgets/multimedia_alert.js +2 -1
  20. data/app/assets/stylesheets/pageflow/admin/tabs_view.scss +3 -3
  21. data/app/assets/stylesheets/pageflow/navigation_mobile.scss +1 -1
  22. data/app/assets/stylesheets/pageflow/page_types/background-image.scss +1 -1
  23. data/app/assets/stylesheets/pageflow/themes/default/anchors.scss +5 -0
  24. data/app/assets/stylesheets/pageflow/themes/default/background_media_unmute_button.scss +45 -36
  25. data/app/assets/stylesheets/pageflow/themes/default/overview/icons/icon_font.scss +4 -1
  26. data/app/assets/stylesheets/pageflow/themes/default/page/anchors.scss +4 -0
  27. data/app/controllers/concerns/pageflow/public_https_mode.rb +5 -1
  28. data/app/controllers/pageflow/entries_controller.rb +10 -4
  29. data/app/jobs/pageflow/upload_file_to_s3_job.rb +1 -1
  30. data/app/models/concerns/pageflow/hosted_file.rb +0 -25
  31. data/app/models/pageflow/widget.rb +20 -9
  32. data/app/views/components/pageflow/admin/revisions_tab.rb +2 -2
  33. data/app/views/components/pageflow/admin/tabs_view.rb +3 -3
  34. data/app/views/pageflow/entries/_entry.html.erb +1 -1
  35. data/app/views/pageflow/entries/show.html.erb +1 -0
  36. data/config/locales/de.yml +2 -0
  37. data/config/locales/en.yml +2 -0
  38. data/lib/pageflow/configuration.rb +10 -0
  39. data/lib/pageflow/primary_domain_entry_redirect.rb +25 -0
  40. data/lib/pageflow/react/widget_type.rb +7 -2
  41. data/lib/pageflow/version.rb +1 -1
  42. data/lib/pageflow/widget_type.rb +8 -0
  43. data/spec/factories/hosted_files.rb +0 -8
  44. metadata +6 -5
  45. data/app/assets/javascripts/pageflow/slideshow/adjacent_preparer.js +0 -53
  46. data/app/assets/javascripts/pageflow/slideshow/progressive_preload.js +0 -42
@@ -7,6 +7,7 @@ pageflow.mediaPlayer.volumeBinding = function(player, settings, options) {
7
7
  var volumeFactor = 'volumeFactor' in options ? options.volumeFactor : 1;
8
8
 
9
9
  player.play = function() {
10
+ player.intendToPlay();
10
11
  player.volume(player.targetVolume());
11
12
  listenToVolumeSetting();
12
13
 
@@ -71,4 +72,4 @@ pageflow.mediaPlayer.volumeBinding = function(player, settings, options) {
71
72
  function onVolumeChange(model, value) {
72
73
  player.fadeVolume(player.targetVolume(), 40);
73
74
  }
74
- };
75
+ };
@@ -12,62 +12,84 @@ pageflow.mediaPlayer.volumeFading.webAudio = function(player, audioContext) {
12
12
 
13
13
  var allowedMinValue = 0.000001;
14
14
 
15
- var originalPlay = player.play;
16
-
17
15
  if (audioContext.state === 'suspended') {
18
16
  pageflow.events.on('background_media:unmute', function() {
19
- audioContext.resume();
20
- });
21
-
22
- audioContext.addEventListener('statechange', function() {
23
17
  player.volume(currentValue);
24
18
  });
25
19
  }
26
20
 
27
- player.play = function(/* arguments */) {
28
- return originalPlay.apply(player, arguments);
29
- };
30
-
31
- player.volume = function(value) {
32
- if (typeof value !== 'undefined') {
21
+ function tryResumeIfSuspended() {
22
+ return new $.Deferred(function(deferred) {
33
23
  if (audioContext.state === 'suspended') {
34
- currentValue = ensureInAllowedRange(value);
35
- return;
24
+ var maybePromise = audioContext.resume();
25
+
26
+ if (maybePromise && maybePromise.then) {
27
+ maybePromise.then(handleDeferred);
28
+ }
29
+ else {
30
+ setTimeout(handleDeferred, 0);
31
+ }
32
+ }
33
+ else {
34
+ deferred.resolve();
36
35
  }
37
36
 
38
- ensureGainNode();
39
-
40
- cancel();
41
- currentValue = ensureInAllowedRange(value);
37
+ function handleDeferred() {
38
+ if (audioContext.state === 'suspended') {
39
+ deferred.reject();
40
+ }
41
+ else {
42
+ deferred.resolve();
43
+ }
44
+ }
45
+ }).promise();
46
+ }
42
47
 
43
- return gainNode.gain.setValueAtTime(currentValue,
44
- audioContext.currentTime);
48
+ player.volume = function(value) {
49
+ if (typeof value !== 'undefined') {
50
+ tryResumeIfSuspended().then(
51
+ function() {
52
+ ensureGainNode();
53
+
54
+ cancel();
55
+ currentValue = ensureInAllowedRange(value);
56
+
57
+ gainNode.gain.setValueAtTime(currentValue,
58
+ audioContext.currentTime);
59
+ },
60
+ function() {
61
+ currentValue = ensureInAllowedRange(value);
62
+ }
63
+ );
45
64
  }
46
65
 
47
66
  return Math.round(currentValue * 100) / 100;
48
67
  };
49
68
 
50
69
  player.fadeVolume = function(value, duration) {
51
- if (audioContext.state === 'suspended') {
52
- currentValue = ensureInAllowedRange(value);
53
- return new $.Deferred().resolve().promise();
54
- }
70
+ return tryResumeIfSuspended().then(
71
+ function() {
72
+ ensureGainNode();
55
73
 
56
- ensureGainNode();
74
+ cancel();
75
+ recordFadeStart(duration);
57
76
 
58
- cancel();
59
- recordFadeStart(duration);
60
-
61
- currentValue = ensureInAllowedRange(value);
77
+ currentValue = ensureInAllowedRange(value);
62
78
 
63
- gainNode.gain.setValueAtTime(lastStartValue, audioContext.currentTime);
64
- gainNode.gain.linearRampToValueAtTime(currentValue,
65
- audioContext.currentTime + duration / 1000);
79
+ gainNode.gain.setValueAtTime(lastStartValue, audioContext.currentTime);
80
+ gainNode.gain.linearRampToValueAtTime(currentValue,
81
+ audioContext.currentTime + duration / 1000);
66
82
 
67
- return new $.Deferred(function(deferred) {
68
- currentTimeout = setTimeout(resolve, duration);
69
- currentDeferred = deferred;
70
- }).promise();
83
+ return new $.Deferred(function(deferred) {
84
+ currentTimeout = setTimeout(resolve, duration);
85
+ currentDeferred = deferred;
86
+ }).promise();
87
+ },
88
+ function() {
89
+ currentValue = ensureInAllowedRange(value);
90
+ return new $.Deferred().resolve().promise();
91
+ }
92
+ );
71
93
  };
72
94
 
73
95
  player.one('dispose', cancel);
@@ -119,9 +141,10 @@ pageflow.mediaPlayer.volumeFading.webAudio = function(player, audioContext) {
119
141
  if (gainNode.gain.value == 1) {
120
142
  var performedDuration = (audioContext.currentTime - lastStartTime) * 1000;
121
143
  var lastDelta = currentValue - lastStartValue;
144
+ var performedFraction = lastDelta > 0 ? performedDuration / lastDuration : 1;
122
145
 
123
146
  currentValue = ensureInAllowedRange(
124
- lastStartValue + (performedDuration / lastDuration * lastDelta)
147
+ lastStartValue + performedFraction * lastDelta
125
148
  );
126
149
  }
127
150
  else {
@@ -6,8 +6,8 @@
6
6
  //=require ./slideshow/scroll_indicator
7
7
  //=require ./slideshow/scroll_indicator_widget
8
8
  //=require ./slideshow/hidden_text_indicator_widget
9
- //=require ./slideshow/progressive_preload
10
- //=require ./slideshow/adjacent_preparer
9
+ //=require ./slideshow/adjacent_preloader
10
+ //=require ./slideshow/successor_preparer
11
11
  //=require ./slideshow/swipe_gesture
12
12
  //=require ./slideshow/hide_text
13
13
  //=require ./slideshow/hide_text_on_swipe
@@ -16,7 +16,6 @@
16
16
 
17
17
  pageflow.Slideshow = function($el, configurations) {
18
18
  var transitioning = false,
19
- preload = new pageflow.ProgressivePreload(),
20
19
  currentPage = $(),
21
20
  pages = $(),
22
21
  that = this,
@@ -127,7 +126,7 @@ pageflow.Slideshow = function($el, configurations) {
127
126
  transition: transition
128
127
  });
129
128
 
130
- preload.start(currentPage);
129
+ currentPage.page('preload');
131
130
  $el.trigger('slideshowchangepage', [options]);
132
131
 
133
132
  return Math.max(outDuration, inDuration);
@@ -176,16 +175,17 @@ pageflow.Slideshow = function($el, configurations) {
176
175
  currentPageIndex = currentPage.index();
177
176
 
178
177
  currentPage.page('activateAsLandingPage');
179
- preload.start(currentPage);
178
+ currentPage.page('preload');
180
179
  }
181
180
  }
182
181
 
183
182
  function findNewCurrentPage(options) {
184
183
  if (!currentPage.length) {
185
184
  var permaId = options && options.landingPagePermaId;
185
+ var landingPage = permaId ? getPageByPermaId(permaId) : $();
186
186
 
187
- return permaId ?
188
- getPageByPermaId(permaId) :
187
+ return landingPage.length ?
188
+ landingPage :
189
189
  that.scrollNavigator.getLandingPage(pages);
190
190
  }
191
191
  else if (!currentPage.parent().length) {
@@ -236,7 +236,14 @@ pageflow.Slideshow = function($el, configurations) {
236
236
  $el.find('.scroll_indicator').scrollIndicator({parent: this});
237
237
 
238
238
  this.scrollNavigator = new pageflow.DomOrderScrollNavigator(this, pageflow.entryData);
239
- this.preparer = pageflow.AdjacentPreparer.create(function() { return pages; }, this.scrollNavigator).attach(pageflow.events);
239
+
240
+ pageflow.AdjacentPreloader
241
+ .create(function() { return pages; }, this.scrollNavigator)
242
+ .attach(pageflow.events);
243
+
244
+ pageflow.SuccessorPreparer
245
+ .create(function() { return pages; }, this.scrollNavigator)
246
+ .attach(pageflow.events);
240
247
  };
241
248
 
242
249
  pageflow.Slideshow.setup = function(options) {
@@ -7,10 +7,10 @@ pageflow.AdjacentPages = pageflow.Object.extend({
7
7
  of: function(page) {
8
8
  var result = [];
9
9
  var pages = this.pages();
10
- var nextPage = this.scrollNavigator.getNextPage(page.element, pages);
10
+ var nextPage = this.nextPage(page);
11
11
 
12
- if (nextPage.length) {
13
- result.push(nextPage.page('instance'));
12
+ if (nextPage) {
13
+ result.push(nextPage);
14
14
  }
15
15
 
16
16
  _(page.linkedPages()).each(function(permaId) {
@@ -22,5 +22,10 @@ pageflow.AdjacentPages = pageflow.Object.extend({
22
22
  }, this);
23
23
 
24
24
  return result;
25
+ },
26
+
27
+ nextPage: function(page) {
28
+ var nextPage = this.scrollNavigator.getNextPage(page.element, this.pages());
29
+ return nextPage.length && nextPage.page('instance');
25
30
  }
26
- });
31
+ });
@@ -0,0 +1,26 @@
1
+ //= require ./adjacent_pages
2
+
3
+ pageflow.AdjacentPreloader = pageflow.Object.extend({
4
+ initialize: function(adjacentPages) {
5
+ this.adjacentPages = adjacentPages;
6
+ },
7
+
8
+ attach: function(events) {
9
+ this.listenTo(events, 'page:change', this.preloadAdjacent);
10
+ },
11
+
12
+ preloadAdjacent: function(page) {
13
+ _(this.adjacentPages.of(page)).each(function(page) {
14
+ page.preload();
15
+ });
16
+ }
17
+ });
18
+
19
+ pageflow.AdjacentPreloader.create = function(pages, scrollNavigator) {
20
+ return new pageflow.AdjacentPreloader(
21
+ new pageflow.AdjacentPages(
22
+ pages,
23
+ scrollNavigator
24
+ )
25
+ );
26
+ };
@@ -1,10 +1,10 @@
1
1
  (function($) {
2
2
  var creatingMethods = [
3
- 'reinit', 'reactivate', 'activate', 'activateAsLandingPage', 'prepare', 'linkedPages'
3
+ 'reinit', 'reactivate', 'activate', 'activateAsLandingPage', 'preload', 'prepare', 'linkedPages'
4
4
  ];
5
5
 
6
6
  var ignoredMethods = [
7
- 'cleanup', 'refreshScroller', 'resize', 'preload', 'deactivate', 'unprepare',
7
+ 'cleanup', 'refreshScroller', 'resize', 'deactivate', 'unprepare',
8
8
  'isPageChangeAllowed'
9
9
  ];
10
10
 
@@ -0,0 +1,49 @@
1
+ //= require ./adjacent_pages
2
+
3
+ pageflow.SuccessorPreparer = pageflow.Object.extend({
4
+ initialize: function(adjacentPages) {
5
+ this.adjacentPages = adjacentPages;
6
+ },
7
+
8
+ attach: function(events) {
9
+ this.listenTo(events, 'page:change', this.schedule);
10
+ },
11
+
12
+ schedule: function(page) {
13
+ clearTimeout(this.scheduleTimeout);
14
+
15
+ var prepare = _.bind(this.prepareSuccessor, this, page);
16
+ this.scheduleTimeout = setTimeout(prepare, page.prepareNextPageTimeout());
17
+ },
18
+
19
+ prepareSuccessor: function(page) {
20
+ var preparedPages = _.compact([
21
+ page,
22
+ this.adjacentPages.nextPage(page)
23
+ ]);
24
+
25
+ var noLongerPreparedPages = _.difference(this.lastPreparedPages, preparedPages);
26
+ var newAdjacentPages = _.difference(preparedPages, this.lastPreparedPages);
27
+
28
+ _(noLongerPreparedPages).each(function(page) {
29
+ if (!page.isDestroyed) {
30
+ page.unprepare();
31
+ }
32
+ });
33
+
34
+ _(newAdjacentPages).each(function(adjacentPage) {
35
+ adjacentPage.prepare();
36
+ });
37
+
38
+ this.lastPreparedPages = preparedPages;
39
+ }
40
+ });
41
+
42
+ pageflow.SuccessorPreparer.create = function(pages, scrollNavigator) {
43
+ return new pageflow.SuccessorPreparer(
44
+ new pageflow.AdjacentPages(
45
+ pages,
46
+ scrollNavigator
47
+ )
48
+ );
49
+ };
@@ -4,6 +4,11 @@
4
4
  * @param {boolean} [options.required=false]
5
5
  * Display an error if the input is blank.
6
6
  *
7
+ * @param {number} [options.maxLength=255]
8
+ * Maximum length of characters for this input.
9
+ * To support legacy data which consists of more characters than the specified maxLength,
10
+ * the option will only take effect for data which is shorter than the specified maxLength.
11
+ *
7
12
  * @see
8
13
  * {@link module:pageflow/ui.pageflow.inputWithPlaceholderText pageflow.inputWithPlaceholderText}
9
14
  * for placeholder related further options
@@ -33,12 +38,15 @@ pageflow.TextInputView = Backbone.Marionette.ItemView.extend({
33
38
  },
34
39
 
35
40
  onChange: function() {
36
- this.validate();
37
- this.save();
41
+ if(this.validate()) {
42
+ this.save();
43
+ }
38
44
  },
39
45
 
40
46
  onClose: function() {
41
- this.save();
47
+ if(this.validate()) {
48
+ this.save();
49
+ }
42
50
  },
43
51
 
44
52
  save: function() {
@@ -46,15 +54,31 @@ pageflow.TextInputView = Backbone.Marionette.ItemView.extend({
46
54
  },
47
55
 
48
56
  load: function() {
49
- this.ui.input.val(this.model.get(this.options.propertyName));
57
+ var input = this.ui.input;
58
+ input.val(this.model.get(this.options.propertyName));
59
+
60
+ // set mysql varchar length as default for non-legacy data
61
+ this.options.maxLength = this.options.maxLength || 255;
62
+ // do not validate legacy data which length exceeds the specified maximum
63
+ // for new and maxLength-conforming data: add validation
64
+ this.validateMaxLength = (input.val().length <= this.options.maxLength);
50
65
  },
51
66
 
52
67
  validate: function() {
53
- if (this.options.required && !this.ui.input.val()) {
68
+ var input = this.ui.input;
69
+ if (this.options.required && !input.val()) {
54
70
  this.displayValidationError(I18n.t('pageflow.ui.views.inputs.text_input_view.required_field'));
71
+ return false;
72
+ } if (this.validateMaxLength && (input.val().length > this.options.maxLength)) {
73
+ this.displayValidationError(
74
+ I18n.t('pageflow.ui.views.inputs.text_input_view.max_characters_exceeded',
75
+ {max_length: this.options.maxLength})
76
+ );
77
+ return false;
55
78
  }
56
79
  else {
57
80
  this.resetValidationError();
81
+ return true;
58
82
  }
59
83
  },
60
84
 
@@ -56,7 +56,7 @@
56
56
  * ### Inline Help for Disabled Inputs
57
57
  *
58
58
  * For each inline help translation key, a separate key with an
59
- * `"_disbaled"` suffix can be supplied, which provides a help string
59
+ * `"_disabled"` suffix can be supplied, which provides a help string
60
60
  * that shall be displayed when the input is disabled. More specific
61
61
  * attribute translation key prefixes take precedence over suffixed
62
62
  * keys:
@@ -23,6 +23,7 @@
23
23
 
24
24
  widget.element.find('.close').one('click', function() {
25
25
  hide();
26
+ pageflow.backgroundMedia.unmute();
26
27
 
27
28
  pageflow.events.trigger('button:close_multimedia_alert');
28
29
  start();
@@ -42,4 +43,4 @@
42
43
  pageflow.nativeScrolling.preventScrollBouncing(this.element);
43
44
  }
44
45
  });
45
- }(jQuery));
46
+ }(jQuery));
@@ -3,7 +3,7 @@
3
3
  background-color: #f4f4f4;
4
4
  @include inset-shadow(0, 1px, 4px, #ddd);
5
5
 
6
- > .tabs {
6
+ &-tabs {
7
7
  @include gradient(#efefef, #dfe1e2);
8
8
  box-shadow: 0 1px 1px rgba(0,0,0,0.10), 0 1px 0 0 rgba(255,255,255, 0.8) inset;
9
9
  border: solid 1px #c7c7c7;
@@ -37,7 +37,7 @@
37
37
  }
38
38
  }
39
39
 
40
- > .tab_container {
40
+ &-container {
41
41
  @include clearfix;
42
42
  @extend .panel_contents;
43
43
 
@@ -48,4 +48,4 @@
48
48
  display: block;
49
49
  }
50
50
  }
51
- }
51
+ }
@@ -132,7 +132,7 @@ body {
132
132
  height: 34px;
133
133
  border-radius: 17px;
134
134
  background-color: rgba(53, 53, 53, 0.9);
135
- @include box-shadow(0 0 7px #ccc);
135
+ box-shadow: 0 0 7px #ccc;
136
136
  z-index: 1;
137
137
  }
138
138
  }