pageflow 15.2.2 → 15.3.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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +338 -85
  3. data/admins/pageflow/accounts.rb +1 -98
  4. data/admins/pageflow/entry.rb +21 -1
  5. data/admins/pageflow/entry_templates.rb +140 -0
  6. data/admins/pageflow/membership.rb +12 -0
  7. data/admins/pageflow/user.rb +5 -3
  8. data/app/assets/javascripts/pageflow/admin/entries.js +65 -0
  9. data/app/assets/javascripts/pageflow/admin/users.js +1 -1
  10. data/app/assets/javascripts/pageflow/asset_urls.js.erb +1 -0
  11. data/app/assets/javascripts/pageflow/base.js +0 -12
  12. data/app/assets/javascripts/pageflow/components.js +2 -6
  13. data/app/assets/javascripts/pageflow/dist/ui.js +47 -14
  14. data/app/assets/javascripts/pageflow/vendor.js +13 -10
  15. data/app/assets/stylesheets/pageflow/base.scss +0 -7
  16. data/app/assets/stylesheets/pageflow/editor/base.scss +2 -0
  17. data/app/assets/stylesheets/pageflow/editor/composables.scss +5 -1
  18. data/app/assets/stylesheets/pageflow/editor/emulation_mode_button.scss +44 -55
  19. data/app/assets/stylesheets/pageflow/editor/help.scss +2 -2
  20. data/app/assets/stylesheets/pageflow/ui/tooltip.scss +17 -3
  21. data/app/helpers/pageflow/admin/entries_helper.rb +16 -0
  22. data/app/helpers/pageflow/structured_data_helper.rb +0 -2
  23. data/app/models/pageflow/account.rb +21 -1
  24. data/app/models/pageflow/entry.rb +9 -2
  25. data/app/models/pageflow/entry_duplicate.rb +1 -0
  26. data/app/models/pageflow/entry_template.rb +16 -2
  27. data/app/policies/pageflow/account_policy.rb +10 -0
  28. data/app/policies/pageflow/entry_template_policy.rb +5 -1
  29. data/app/views/admin/accounts/_entry_template_details.html.arb +7 -5
  30. data/app/views/admin/accounts/_form.html.erb +3 -49
  31. data/app/views/admin/entries/_attributes_table.html.arb +5 -0
  32. data/app/views/admin/entries/_not_allowed_to_see_entry_types.json.jbuilder +2 -0
  33. data/app/views/admin/entries/entry_types.json.jbuilder +4 -0
  34. data/app/views/admin/entry_templates/_form.html.erb +58 -0
  35. data/app/views/admin/users/_not_allowed_to_see_user_quota.html.erb +3 -0
  36. data/app/views/components/pageflow/admin/entry_templates_tab.rb +48 -0
  37. data/app/views/pageflow/admin/users/_quota_exhausted.html.erb +1 -1
  38. data/config/initializers/admin_resource_tabs.rb +5 -0
  39. data/config/initializers/help_entries.rb +1 -5
  40. data/config/locales/de.yml +88 -155
  41. data/config/locales/en.yml +79 -143
  42. data/db/migrate/20200515112500_add_constraints_to_entry_templates.rb +21 -0
  43. data/db/migrate/20200807135200_rename_pageflow_entry_template_entry_type_to_entry_type_name.rb +7 -0
  44. data/entry_types/paged/app/assets/javascripts/pageflow_paged/components.js +7 -0
  45. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +1479 -1391
  46. data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +9218 -0
  47. data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-client.js +1 -1
  48. data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-server.js +3 -3
  49. data/entry_types/paged/app/assets/javascripts/pageflow_paged/frontend.js +6 -0
  50. data/entry_types/paged/app/assets/javascripts/pageflow_paged/server_rendering.js +9 -0
  51. data/entry_types/paged/app/assets/javascripts/pageflow_paged/vendor.js +8 -0
  52. data/entry_types/paged/app/controllers/pageflow_paged/application_controller.rb +2 -2
  53. data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/page_background_asset_helper.rb +4 -3
  54. data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/react_server_side_rendering_helper.rb +23 -2
  55. data/entry_types/paged/app/views/layouts/pageflow_paged/application.html.erb +2 -2
  56. data/entry_types/paged/app/views/pageflow_paged/editor/entries/_head.html.erb +2 -2
  57. data/entry_types/paged/app/views/pageflow_paged/entries/_entry.html.erb +1 -1
  58. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/page_background_asset/_element.html.erb +0 -0
  59. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/_widget.html.erb +0 -0
  60. data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/page.html.erb +0 -0
  61. data/entry_types/paged/config/initializers/features.rb +1 -1
  62. data/entry_types/paged/config/initializers/help_entries.rb +17 -0
  63. data/entry_types/paged/config/locales/new/help.de.yml +162 -0
  64. data/entry_types/paged/config/locales/new/help.en.yml +153 -0
  65. data/entry_types/paged/lib/pageflow_paged/engine.rb +13 -0
  66. data/entry_types/paged/lib/pageflow_paged/plugin.rb +5 -1
  67. data/entry_types/paged/lib/pageflow_paged/react.rb +12 -0
  68. data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/page_type.rb +2 -2
  69. data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/widget_type.rb +2 -2
  70. data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react-server.js +20613 -0
  71. data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react.js +21495 -0
  72. data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react-server.js +24 -0
  73. data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react.js +24 -0
  74. data/entry_types/scrolled/app/assets/javascripts/pageflow_scrolled/legacy.js +0 -0
  75. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +2 -2
  76. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +14 -4
  77. data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -2
  78. data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +8 -0
  79. data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +6 -0
  80. data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +2 -0
  81. data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +33 -0
  82. data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +8 -0
  83. data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +38 -0
  84. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/content_elements/batch.json.jbuilder +2 -0
  85. data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -7
  86. data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +19 -3
  87. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +3 -0
  88. data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +7 -0
  89. data/entry_types/scrolled/config/initializers/help_entries.rb +16 -0
  90. data/entry_types/scrolled/config/locales/new/de.yml +345 -13
  91. data/entry_types/scrolled/config/locales/new/en.yml +257 -14
  92. data/entry_types/scrolled/config/routes.rb +1 -0
  93. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +28 -0
  94. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDesktop.svg +56 -0
  95. data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoMobile.svg +22 -0
  96. data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +4 -0
  97. data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +3 -1
  98. data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +90 -30
  99. data/entry_types/scrolled/lib/tasks/pageflow_scrolled_tasks.rake +64 -27
  100. data/entry_types/scrolled/package/contentElements-editor.js +242 -183
  101. data/entry_types/scrolled/package/contentElements-frontend.css +1 -0
  102. data/entry_types/scrolled/package/contentElements-frontend.js +624 -279
  103. data/entry_types/scrolled/package/editor.js +2561 -363
  104. data/entry_types/scrolled/package/frontend-server.js +228 -0
  105. data/entry_types/scrolled/package/frontend/EditableText-4264c349.js +1993 -0
  106. data/entry_types/scrolled/package/frontend/Wavesurfer-c3c45324.js +378 -0
  107. data/entry_types/scrolled/package/frontend/components-cfe6a479.js +2115 -0
  108. data/entry_types/scrolled/package/frontend/getPrototypeOf-63c7c8e8.js +86 -0
  109. data/entry_types/scrolled/package/frontend/index.css +9 -0
  110. data/entry_types/scrolled/package/frontend/index.js +4425 -0
  111. data/entry_types/scrolled/package/package.json +17 -6
  112. data/entry_types/scrolled/spec/fixtures/audio.m4a +0 -0
  113. data/entry_types/scrolled/spec/fixtures/video.mp4 +0 -0
  114. data/lib/generators/pageflow/initializer/templates/pageflow.rb +20 -9
  115. data/lib/pageflow/ability_mixin.rb +14 -2
  116. data/lib/pageflow/configuration.rb +6 -5
  117. data/lib/pageflow/engine.rb +1 -0
  118. data/lib/pageflow/entry_type_configuration.rb +1 -0
  119. data/lib/pageflow/global_config_api.rb +5 -4
  120. data/lib/pageflow/react.rb +4 -2
  121. data/lib/pageflow/version.rb +1 -1
  122. data/{packages/pageflow → package}/config/jest/index.js +2 -1
  123. data/{packages/pageflow → package}/config/jest/transformers/jst.js +0 -0
  124. data/{packages/pageflow → package}/config/jest/transformers/upwardBabel.js +0 -0
  125. data/package/config/webpack.js +22 -0
  126. data/{packages/pageflow → package}/editor.js +480 -1129
  127. data/package/frontend.js +2525 -0
  128. data/{packages/pageflow → package}/package.json +3 -0
  129. data/{packages/pageflow → package}/testHelpers.js +114 -13
  130. data/{packages/pageflow → package}/ui.js +47 -14
  131. data/spec/factories/accounts.rb +3 -1
  132. data/spec/factories/entry_templates.rb +1 -0
  133. data/spec/factories/published_entries.rb +6 -1
  134. metadata +62 -26
  135. data/app/assets/javascripts/pageflow/dist/frontend.js +0 -5800
  136. data/config/initializers/entry_types.rb +0 -4
  137. data/entry_types/scrolled/package/frontend.js +0 -2879
  138. data/packages/pageflow/config/jest/transformers/cssModules.js +0 -1
  139. data/packages/pageflow/config/webpack.js +0 -14
@@ -0,0 +1,2525 @@
1
+ import 'core-js/modules/es.array.from';
2
+ import 'core-js/modules/es.array.includes';
3
+ import 'core-js/modules/es.object.assign';
4
+ import 'core-js/modules/es.object.entries';
5
+ import 'core-js/modules/es.object.keys';
6
+ import 'core-js/modules/es.object.to-string';
7
+ import 'core-js/modules/es.promise';
8
+ import 'core-js/modules/es.promise.finally';
9
+ import 'core-js/modules/es.string.iterator';
10
+ import 'core-js/modules/esnext.aggregate-error';
11
+ import 'core-js/modules/esnext.promise.all-settled';
12
+ import 'core-js/modules/esnext.promise.any';
13
+ import 'core-js/modules/esnext.promise.try';
14
+ import 'core-js/modules/web.dom-collections.iterator';
15
+ import 'classlist.js';
16
+ import BackboneEvents from 'backbone-events-standalone';
17
+ import VideoJS from 'videojs';
18
+
19
+ var log = function log(text, options) {
20
+ if (window.console && (debugMode() || options && options.force)) {
21
+ window.console.log(text);
22
+ }
23
+ };
24
+ var debugMode = function debugMode() {
25
+ return window.location.href.indexOf('debug=true') >= 0;
26
+ };
27
+
28
+ var state = typeof window !== 'undefined' && window.pageflow || {};
29
+
30
+ var assetUrls = state.assetUrls || {};
31
+
32
+ // https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
33
+ var cookies = {
34
+ getItem: function getItem(sKey) {
35
+ if (!sKey) {
36
+ return null;
37
+ } // eslint-disable-next-line no-useless-escape
38
+
39
+
40
+ return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
41
+ },
42
+ setItem: function setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
43
+ // eslint-disable-next-line no-useless-escape
44
+ if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
45
+ return false;
46
+ }
47
+
48
+ var sExpires = "";
49
+
50
+ if (vEnd) {
51
+ switch (vEnd.constructor) {
52
+ case Number:
53
+ sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
54
+ break;
55
+
56
+ case String:
57
+ sExpires = "; expires=" + vEnd;
58
+ break;
59
+
60
+ case Date:
61
+ sExpires = "; expires=" + vEnd.toUTCString();
62
+ break;
63
+ }
64
+ }
65
+
66
+ document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
67
+ return true;
68
+ },
69
+ removeItem: function removeItem(sKey, sPath, sDomain) {
70
+ if (!this.hasItem(sKey)) {
71
+ return false;
72
+ }
73
+
74
+ document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
75
+ return true;
76
+ },
77
+ hasItem: function hasItem(sKey) {
78
+ if (!sKey) {
79
+ return false;
80
+ } // eslint-disable-next-line no-useless-escape
81
+
82
+
83
+ return new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(document.cookie);
84
+ },
85
+ keys: function keys() {
86
+ // eslint-disable-next-line no-useless-escape
87
+ var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
88
+
89
+ for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) {
90
+ aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
91
+ }
92
+
93
+ return aKeys;
94
+ }
95
+ };
96
+
97
+ var events = Object.assign({}, BackboneEvents);
98
+
99
+ /**
100
+ * Detect browser via user agent. Use only if feature detection is not
101
+ * an option.
102
+ */
103
+ var Agent = function Agent(userAgent) {
104
+ return {
105
+ matchesSilk: function matchesSilk() {
106
+ return matches(/\bSilk\b/);
107
+ },
108
+ matchesDesktopSafari: function matchesDesktopSafari(options) {
109
+ if (options) {
110
+ return this.matchesSafari() && !this.matchesMobilePlatform() && matchesMinVersion(/Version\/(\d+)/i, options.minVersion);
111
+ } else {
112
+ return this.matchesSafari() && !this.matchesMobilePlatform();
113
+ }
114
+ },
115
+ matchesDesktopSafari9: function matchesDesktopSafari9() {
116
+ return this.matchesSafari9() && !this.matchesMobilePlatform();
117
+ },
118
+ matchesDesktopSafari10: function matchesDesktopSafari10() {
119
+ return this.matchesSafari10() && !this.matchesMobilePlatform();
120
+ },
121
+ matchesSafari9: function matchesSafari9() {
122
+ return this.matchesSafari() && matches(/Version\/9/i);
123
+ },
124
+ matchesSafari10: function matchesSafari10() {
125
+ return this.matchesSafari() && matches(/Version\/10/i);
126
+ },
127
+ matchesSafari11: function matchesSafari11() {
128
+ return this.matchesSafari() && matches(/Version\/11/i);
129
+ },
130
+ matchesSafari11AndAbove: function matchesSafari11AndAbove() {
131
+ return this.matchesSafari() && matchesMinVersion(/Version\/(\d+)/i, 11);
132
+ },
133
+ matchesSafari: function matchesSafari() {
134
+ // - Chrome also reports to be a Safari
135
+ // - Safari does not report to be a Chrome
136
+ // - Edge also reports to be a Safari, but also reports to be Chrome
137
+ return matches(/Safari\//i) && !matches(/Chrome/i);
138
+ },
139
+
140
+ /**
141
+ * Returns true on iOS Safari.
142
+ * @return {boolean}
143
+ */
144
+ matchesMobileSafari: function matchesMobileSafari() {
145
+ var matchers = [/iPod/i, /iPad/i, /iPhone/i];
146
+ return matchers.some(function (matcher) {
147
+ return userAgent.match(matcher);
148
+ }) && !window.MSStream || //IE exclusion from being detected as an iOS device;
149
+ matchesiPadSafari13AndAbove();
150
+ },
151
+
152
+ /**
153
+ * Returns true on iOS or Android.
154
+ * @return {boolean}
155
+ */
156
+ matchesMobilePlatform: function matchesMobilePlatform() {
157
+ var matchers = [/iPod/i, /iPad/i, /iPhone/i, /Android/i, /Silk/i, /IEMobile/i];
158
+ return matchers.some(function (matcher) {
159
+ return userAgent.match(matcher);
160
+ }) || matchesiPadSafari13AndAbove();
161
+ },
162
+
163
+ /**
164
+ * Returns true on Internet Explorser version 9, 10 and 11.
165
+ * @return {boolean}
166
+ */
167
+ matchesIEUpTo11: function matchesIEUpTo11() {
168
+ return userAgent.match(/Trident\//);
169
+ },
170
+
171
+ /**
172
+ * Returns true in InApp browser of Facebook app.
173
+ * @return {boolean}
174
+ */
175
+ matchesFacebookInAppBrowser: function matchesFacebookInAppBrowser() {
176
+ return userAgent.match(/FBAN/) && userAgent.match(/FBAV/);
177
+ },
178
+ matchesDesktopChrome: function matchesDesktopChrome(options) {
179
+ if (options) {
180
+ return this.matchesChrome() && !this.matchesMobilePlatform() && matchesMinVersion(/Chrome\/(\d+)/i, options.minVersion);
181
+ } else {
182
+ return this.matchesChrome() && !this.matchesMobilePlatform();
183
+ }
184
+ },
185
+ matchesDesktopFirefox: function matchesDesktopFirefox(options) {
186
+ if (options) {
187
+ return this.matchesFirefox() && !this.matchesMobilePlatform() && matchesMinVersion(/Firefox\/(\d+)/i, options.minVersion);
188
+ } else {
189
+ return this.matchesFirefox() && !this.matchesMobilePlatform();
190
+ }
191
+ },
192
+ matchesDesktopEdge: function matchesDesktopEdge(options) {
193
+ if (options) {
194
+ return this.matchesEdge() && !this.matchesMobilePlatform() && matchesMinVersion(/Edg\/(\d+)/i, options.minVersion);
195
+ } else {
196
+ return this.matchesEdge() && !this.matchesMobilePlatform();
197
+ }
198
+ },
199
+
200
+ /**
201
+ * Returns true on Google Chrome.
202
+ * @return {boolean}
203
+ */
204
+ matchesChrome: function matchesChrome() {
205
+ // - Edge also reports to be a Chrome
206
+ return matches(/Chrome\//i) && !matches(/Edg/i);
207
+ },
208
+
209
+ /**
210
+ * Returns true on Firefox.
211
+ * @return {boolean}
212
+ */
213
+ matchesFirefox: function matchesFirefox() {
214
+ return matches(/Firefox\//i) && !matches(/Seamonkey/i);
215
+ },
216
+
217
+ /**
218
+ * Returns true on Microsoft Edge.
219
+ * @return {boolean}
220
+ */
221
+ matchesEdge: function matchesEdge() {
222
+ return matches(/Edg\//i);
223
+ }
224
+ };
225
+
226
+ function matches(exp) {
227
+ return !!userAgent.match(exp);
228
+ }
229
+
230
+ function matchesMinVersion(exp, version) {
231
+ var match = userAgent.match(exp);
232
+ return match && match[1] && parseInt(match[1], 10) >= version;
233
+ } //After ios13 update, iPad reports the same user string
234
+ //as Safari on Dekstop MacOS.
235
+ //At the time of this writing there are no other devices
236
+ //with multi-touch support other than IOS/iPadOS
237
+ //See: https://stackoverflow.com/a/58064481
238
+
239
+
240
+ function matchesiPadSafari13AndAbove() {
241
+ return agent.matchesSafari() && navigator.maxTouchPoints > 1 && navigator.platform === 'MacIntel';
242
+ }
243
+ };
244
+ var agent = new Agent(typeof navigator !== 'undefined' ? navigator.userAgent : 'ssr');
245
+
246
+ /**
247
+ * Browser feature detection.
248
+ *
249
+ * @since 0.9
250
+ */
251
+
252
+ var browser = function () {
253
+ var tests = {},
254
+ results = {},
255
+ featureDetectionComplete = false;
256
+ var readyPromiseResolve;
257
+ var readyPromise = new Promise(function (resolve, reject) {
258
+ readyPromiseResolve = resolve;
259
+ });
260
+ return {
261
+ off: {},
262
+ on: {},
263
+ unset: {},
264
+
265
+ /**
266
+ * Add a feature test.
267
+ *
268
+ * @param name [String] Name of the feature. Can contain whitespace.
269
+ * @param test [Function] A function that either returns `true` or
270
+ * `false` or a promise that resolves to `true` or `false`.
271
+ * @memberof pageflow.browser
272
+ */
273
+ feature: function feature(name, test) {
274
+ var s = name.replace(/ /g, '_');
275
+
276
+ this.off[s] = function () {
277
+ window.localStorage['override ' + name] = 'off';
278
+ log('Feature off: ' + name, {
279
+ force: true
280
+ });
281
+ };
282
+
283
+ this.on[s] = function () {
284
+ window.localStorage['override ' + name] = 'on';
285
+ log('Feature on: ' + name, {
286
+ force: true
287
+ });
288
+ };
289
+
290
+ this.unset[s] = function () {
291
+ window.localStorage.removeItem('override ' + name);
292
+ log('Feature unset: ' + name, {
293
+ force: true
294
+ });
295
+ };
296
+
297
+ tests[name] = test;
298
+ },
299
+
300
+ /**
301
+ * Check whether the browser has a specific feature. This method
302
+ * may only be called after the `#ready` promise is resolved.
303
+ *
304
+ * @param name [String] Name of the feature.
305
+ * @return [Boolean]
306
+ * @memberof pageflow.browser
307
+ */
308
+ has: function has(name) {
309
+ if (!featureDetectionComplete) {
310
+ throw 'Feature detection has not finished yet.';
311
+ }
312
+
313
+ if (results[name] === undefined) {
314
+ throw 'Unknown feature "' + name + '".';
315
+ }
316
+
317
+ return results[name];
318
+ },
319
+
320
+ /**
321
+ * A promise that is resolved once feature detection has finished.
322
+ *
323
+ * @return Promise
324
+ * @memberof pageflow.browser
325
+ */
326
+ ready: function ready() {
327
+ return readyPromise;
328
+ },
329
+
330
+ /** @api private */
331
+ detectFeatures: function detectFeatures() {
332
+ var promises = {};
333
+
334
+ var asyncHas = function asyncHas(name) {
335
+ var runTest = function runTest() {
336
+ var value,
337
+ underscoredName = name.replace(/ /g, '_');
338
+
339
+ if (debugMode() && location.href.indexOf('&has=' + underscoredName) >= 0) {
340
+ value = location.href.indexOf('&has=' + underscoredName + '_on') >= 0;
341
+ log('FEATURE OVERRIDDEN ' + name + ': ' + value, {
342
+ force: true
343
+ });
344
+ return value;
345
+ } else if ((debugMode() || window.PAGEFLOW_ALLOW_FEATURE_OVERRIDES) && window.localStorage && typeof window.localStorage['override ' + name] !== 'undefined') {
346
+ value = window.localStorage['override ' + name] === 'on';
347
+ log('FEATURE OVERRIDDEN ' + name + ': ' + value, {
348
+ force: true
349
+ });
350
+ return value;
351
+ } else {
352
+ return tests[name](asyncHas);
353
+ }
354
+ };
355
+
356
+ promises[name] = promises[name] || Promise.all([runTest()]).then(function (a) {
357
+ return a[0];
358
+ });
359
+ return promises[name];
360
+ };
361
+
362
+ asyncHas.not = function (name) {
363
+ return asyncHas(name).then(function (result) {
364
+ return !result;
365
+ });
366
+ };
367
+
368
+ asyncHas.all = function ()
369
+ /* arguments */
370
+ {
371
+ return Promise.all(arguments).then(function (results) {
372
+ return results.every(function (result) {
373
+ return result;
374
+ });
375
+ });
376
+ };
377
+
378
+ Promise.all(Object.keys(tests).map(function (name) {
379
+ return asyncHas(name).then(function (result) {
380
+ var cssClassName = name.replace(/ /g, '_');
381
+ document.body.classList.toggle('has_' + cssClassName, !!result);
382
+ document.body.classList.toggle('has_no_' + cssClassName, !result);
383
+ results[name] = !!result;
384
+ });
385
+ })).then(function () {
386
+ featureDetectionComplete = true;
387
+ readyPromiseResolve();
388
+ });
389
+ return this.ready();
390
+ }
391
+ };
392
+ }();
393
+
394
+ browser.feature('autoplay support', function (has) {
395
+ return !agent.matchesSafari11AndAbove() && !agent.matchesMobilePlatform();
396
+ });
397
+
398
+ browser.feature('css animations', function () {
399
+ var prefixes = ['Webkit', 'Moz', 'O', 'ms', 'Khtml'],
400
+ elm = document.createElement('div');
401
+
402
+ if (elm.style.animationName !== undefined) {
403
+ return true;
404
+ }
405
+
406
+ for (var i = 0; i < prefixes.length; i++) {
407
+ if (elm.style[prefixes[i] + 'AnimationName'] !== undefined) {
408
+ return true;
409
+ }
410
+ }
411
+
412
+ return false;
413
+ });
414
+
415
+ // phone which hides parts of the browser viewport. Normally this is
416
+ // hidden once the user scrolls, but since there is no native
417
+ // scrolling in Pageflow, the bar stays and hides page elements like
418
+ // the slim player controls.
419
+
420
+ browser.feature('facebook toolbar', function (has) {
421
+ return has.all(has('iphone platform'), agent.matchesFacebookInAppBrowser());
422
+ });
423
+
424
+ browser.feature('ie', function () {
425
+ if (navigator.appName == 'Microsoft Internet Explorer') {
426
+ return true;
427
+ } else {
428
+ return false;
429
+ }
430
+ });
431
+
432
+ browser.feature('ios platform', function () {
433
+ return agent.matchesMobileSafari();
434
+ });
435
+ browser.feature('iphone platform', function (has) {
436
+ return has.all(has('ios platform'), has('phone platform'));
437
+ });
438
+
439
+ browser.feature('mobile platform', function () {
440
+ return agent.matchesMobilePlatform();
441
+ });
442
+
443
+ browser.feature('phone platform', function () {
444
+ var matchers = [/iPod/i, /iPad/i, /iPhone/i, /Android/i, /IEMobile/i];
445
+ return matchers.some(function (matcher) {
446
+ return navigator.userAgent.match(matcher) && window.innerWidth < 700;
447
+ });
448
+ });
449
+
450
+ browser.feature('pushstate support', function () {
451
+ return window.history && 'pushState' in window.history;
452
+ });
453
+
454
+ browser.feature('request animation frame support', function () {
455
+ return 'requestAnimationFrame' in window || 'web';
456
+ });
457
+
458
+ browser.feature('touch support', function () {
459
+ return 'ontouchstart' in window ||
460
+ /* Firefox on android */
461
+ window.DocumentTouch && document instanceof window.DocumentTouch ||
462
+ /* > 0 on IE touch devices */
463
+ navigator.maxTouchPoints;
464
+ });
465
+
466
+ browser.feature('rewrite video sources support', function () {
467
+ // set from conditionally included script file
468
+ return !state.ie9;
469
+ });
470
+ browser.feature('stop buffering support', function (has) {
471
+ return has.not('mobile platform');
472
+ });
473
+ browser.feature('buffer underrun waiting support', function (has) {
474
+ return has.not('mobile platform');
475
+ });
476
+ browser.feature('prebuffering support', function (has) {
477
+ return has.not('mobile platform');
478
+ });
479
+ browser.feature('mp4 support only', function (has) {
480
+ // - Silk does not play videos with hls source
481
+ // - Desktop Safari 9.1 does not loop hls videos
482
+ // - Desktop Safari 10 does not loop hls videos on El
483
+ // Capitan. Appears to be fixed on Sierra
484
+ return agent.matchesSilk() || agent.matchesDesktopSafari9() || agent.matchesDesktopSafari10();
485
+ });
486
+ browser.feature('mse and native hls support', function (has) {
487
+ return agent.matchesSafari() && !agent.matchesMobilePlatform();
488
+ });
489
+ browser.feature('native video player', function (has) {
490
+ return has('iphone platform');
491
+ });
492
+
493
+ browser.feature('volume control support', function (has) {
494
+ return has.not('ios platform');
495
+ });
496
+ browser.feature('audio context volume fading support', function () {
497
+ return !agent.matchesDesktopSafari();
498
+ });
499
+
500
+ browser.agent = agent;
501
+ browser.Agent = Agent;
502
+
503
+ function _classCallCheck(instance, Constructor) {
504
+ if (!(instance instanceof Constructor)) {
505
+ throw new TypeError("Cannot call a class as a function");
506
+ }
507
+ }
508
+
509
+ function _defineProperties(target, props) {
510
+ for (var i = 0; i < props.length; i++) {
511
+ var descriptor = props[i];
512
+ descriptor.enumerable = descriptor.enumerable || false;
513
+ descriptor.configurable = true;
514
+ if ("value" in descriptor) descriptor.writable = true;
515
+ Object.defineProperty(target, descriptor.key, descriptor);
516
+ }
517
+ }
518
+
519
+ function _createClass(Constructor, protoProps, staticProps) {
520
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
521
+ if (staticProps) _defineProperties(Constructor, staticProps);
522
+ return Constructor;
523
+ }
524
+
525
+ /**
526
+ * Let plugins register functions which extend the editor or
527
+ * slideshow with certain functionality when a named feature is
528
+ * enabled.
529
+ *
530
+ * @alias pageflow.features
531
+ * @since 0.9
532
+ */
533
+
534
+ var Features =
535
+ /*#__PURE__*/
536
+ function () {
537
+ /** @lends pageflow.features */
538
+
539
+ /** @api private */
540
+ function Features() {
541
+ _classCallCheck(this, Features);
542
+
543
+ this.registry = {};
544
+ this.enabledFeatureNames = [];
545
+ }
546
+ /**
547
+ * `pageflow.features` has been renamed to `pageflow.browser`.
548
+ * @deprecated
549
+ */
550
+
551
+
552
+ _createClass(Features, [{
553
+ key: "has",
554
+ value: function has()
555
+ /* arguments */
556
+ {
557
+ return browser.has.apply(browser, arguments);
558
+ }
559
+ /**
560
+ * Register a function to configure a feature when it is active.
561
+ *
562
+ * @param {String} scope - Name of the scope the passed function
563
+ * shall be called in.
564
+ * @param name [String] Name of the feature
565
+ * @param fn [Function] Function to call when the given feature
566
+ * is activate.
567
+ */
568
+
569
+ }, {
570
+ key: "register",
571
+ value: function register(scope, name, fn) {
572
+ this.registry[scope] = this.registry[scope] || {};
573
+ this.registry[scope][name] = this.registry[scope][name] || [];
574
+ this.registry[scope][name].push(fn);
575
+ }
576
+ /**
577
+ * Check if a feature as been enabled.
578
+ *
579
+ * @param name [String]
580
+ * @return [Boolean]
581
+ */
582
+
583
+ }, {
584
+ key: "isEnabled",
585
+ value: function isEnabled(name) {
586
+ return this.enabledFeatureNames.includes(name);
587
+ }
588
+ /** @api private */
589
+
590
+ }, {
591
+ key: "enable",
592
+ value: function enable(scope, names) {
593
+ var fns = this.registry[scope] || {};
594
+ this.enabledFeatureNames = this.enabledFeatureNames.concat(names);
595
+ names.forEach(function (name) {
596
+ (fns[name] || []).forEach(function (fn) {
597
+ fn();
598
+ });
599
+ });
600
+ }
601
+ }]);
602
+
603
+ return Features;
604
+ }();
605
+ var features = new Features();
606
+
607
+ function _defineProperty(obj, key, value) {
608
+ if (key in obj) {
609
+ Object.defineProperty(obj, key, {
610
+ value: value,
611
+ enumerable: true,
612
+ configurable: true,
613
+ writable: true
614
+ });
615
+ } else {
616
+ obj[key] = value;
617
+ }
618
+
619
+ return obj;
620
+ }
621
+
622
+ function ownKeys(object, enumerableOnly) {
623
+ var keys = Object.keys(object);
624
+
625
+ if (Object.getOwnPropertySymbols) {
626
+ var symbols = Object.getOwnPropertySymbols(object);
627
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
628
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
629
+ });
630
+ keys.push.apply(keys, symbols);
631
+ }
632
+
633
+ return keys;
634
+ }
635
+
636
+ function _objectSpread2(target) {
637
+ for (var i = 1; i < arguments.length; i++) {
638
+ var source = arguments[i] != null ? arguments[i] : {};
639
+
640
+ if (i % 2) {
641
+ ownKeys(Object(source), true).forEach(function (key) {
642
+ _defineProperty(target, key, source[key]);
643
+ });
644
+ } else if (Object.getOwnPropertyDescriptors) {
645
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
646
+ } else {
647
+ ownKeys(Object(source)).forEach(function (key) {
648
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
649
+ });
650
+ }
651
+ }
652
+
653
+ return target;
654
+ }
655
+
656
+ var handleFailedPlay = function handleFailedPlay(player, options) {
657
+ var originalPlay = player.play;
658
+
659
+ player.play = function ()
660
+ /* arguments */
661
+ {
662
+ var result = originalPlay.apply(player, arguments);
663
+
664
+ if (result && typeof result["catch"] !== 'undefined') {
665
+ return result["catch"](function (e) {
666
+ if (e.name === 'NotAllowedError' && options.hasAutoplaySupport) {
667
+ if (options.fallbackToMutedAutoplay) {
668
+ player.muted(true);
669
+ return originalPlay.apply(player, arguments).then(function () {
670
+ player.trigger('playmuted');
671
+ }, function () {
672
+ player.trigger('playfailed');
673
+ });
674
+ } else {
675
+ player.trigger('playfailed');
676
+ }
677
+ } else {
678
+ log('Caught play exception for video.');
679
+ }
680
+ });
681
+ }
682
+
683
+ return result;
684
+ };
685
+ };
686
+
687
+ var asyncPlay = function asyncPlay(player) {
688
+ var originalPlay = player.play;
689
+ var originalPause = player.pause;
690
+ var intendingToPlay = false;
691
+ var intendingToPause = false;
692
+
693
+ player.play = function ()
694
+ /* arguments */
695
+ {
696
+ player.intendToPlay();
697
+ return originalPlay.apply(player, arguments);
698
+ };
699
+
700
+ player.pause = function ()
701
+ /* arguments */
702
+ {
703
+ player.intendToPause();
704
+ return originalPause.apply(player, arguments);
705
+ };
706
+
707
+ player.intendToPlay = function () {
708
+ intendingToPlay = true;
709
+ intendingToPause = false;
710
+ };
711
+
712
+ player.intendToPause = function () {
713
+ intendingToPause = true;
714
+ intendingToPlay = false;
715
+ };
716
+
717
+ player.intendingToPlay = function () {
718
+ return intendingToPlay;
719
+ };
720
+
721
+ player.intendingToPause = function () {
722
+ return intendingToPause;
723
+ };
724
+
725
+ player.ifIntendingToPause = function () {
726
+ return promiseFromBoolean(intendingToPause);
727
+ };
728
+
729
+ player.ifIntendingToPlay = function () {
730
+ return promiseFromBoolean(intendingToPlay);
731
+ };
732
+
733
+ function promiseFromBoolean(value) {
734
+ return new Promise(function (resolve, reject) {
735
+ if (value) {
736
+ resolve();
737
+ } else {
738
+ reject('aborted');
739
+ }
740
+ });
741
+ }
742
+ };
743
+
744
+ var hooks = function hooks(player, _hooks) {
745
+ var originalPlay = player.play;
746
+
747
+ player.updateHooks = function (newHooks) {
748
+ _hooks = newHooks;
749
+ };
750
+
751
+ player.play = function ()
752
+ /* args */
753
+ {
754
+ var args = arguments;
755
+ player.trigger('beforeplay');
756
+ player.intendToPlay();
757
+
758
+ if (_hooks.before) {
759
+ return Promise.all([_hooks.before()]).then(function () {
760
+ return player.ifIntendingToPlay().then(function () {
761
+ return originalPlay.apply(player, args);
762
+ });
763
+ });
764
+ } else {
765
+ return originalPlay.apply(player, args);
766
+ }
767
+ };
768
+
769
+ if (player.afterHookListener) {
770
+ player.off('pause', player.afterHookListener);
771
+ player.off('ended', player.afterHookListener);
772
+ }
773
+
774
+ player.afterHookListener = function () {
775
+ if (_hooks.after) {
776
+ _hooks.after();
777
+ }
778
+ };
779
+
780
+ player.on('pause', player.afterHookListener);
781
+ player.on('ended', player.afterHookListener);
782
+ };
783
+
784
+ var volumeBinding = function volumeBinding(player, settings, options) {
785
+ options = options || {};
786
+ var originalPlay = player.play;
787
+ var originalPause = player.pause;
788
+ var volumeFactor = 'volumeFactor' in options ? options.volumeFactor : 1;
789
+
790
+ player.play = function () {
791
+ player.intendToPlay();
792
+ player.volume(player.targetVolume());
793
+ listenToVolumeSetting();
794
+ return originalPlay.call(player);
795
+ };
796
+
797
+ player.playAndFadeIn = function (duration) {
798
+ if (!player.paused() && !player.intendingToPause()) {
799
+ return Promise.resolve();
800
+ }
801
+
802
+ player.intendToPlay();
803
+ player.volume(0);
804
+ return Promise.all([originalPlay.call(player)]).then(function () {
805
+ listenToVolumeSetting();
806
+ return player.ifIntendingToPlay().then(function () {
807
+ return player.fadeVolume(player.targetVolume(), duration).then(null, function () {
808
+ return Promise.resolve();
809
+ });
810
+ });
811
+ });
812
+ };
813
+
814
+ player.pause = function () {
815
+ stopListeningToVolumeSetting();
816
+ originalPause.call(player);
817
+ };
818
+
819
+ player.fadeOutAndPause = function (duration) {
820
+ if (player.paused() && !player.intendingToPlay()) {
821
+ return Promise.resolve();
822
+ }
823
+
824
+ player.intendToPause();
825
+ stopListeningToVolumeSetting();
826
+ return player.fadeVolume(0, duration).then(function () {
827
+ return player.ifIntendingToPause().then(function () {
828
+ originalPause.call(player);
829
+ });
830
+ });
831
+ };
832
+
833
+ player.changeVolumeFactor = function (factor, duration) {
834
+ volumeFactor = factor;
835
+ return player.fadeVolume(player.targetVolume(), duration);
836
+ };
837
+
838
+ player.targetVolume = function () {
839
+ return settings.get('volume') * volumeFactor;
840
+ };
841
+
842
+ function listenToVolumeSetting() {
843
+ player.on('dispose', stopListeningToVolumeSetting);
844
+ settings.on('change:volume', onVolumeChange);
845
+ }
846
+
847
+ function stopListeningToVolumeSetting() {
848
+ player.off('dispose', stopListeningToVolumeSetting);
849
+ settings.off('change:volume', onVolumeChange);
850
+ }
851
+
852
+ function onVolumeChange(model, value) {
853
+ player.fadeVolume(player.targetVolume(), 40);
854
+ }
855
+ };
856
+
857
+ /**
858
+ * Obtain the globally shared audio context. There can only be a
859
+ * limited number of `AudioContext` objects in one page.
860
+ *
861
+ * @since 12.1
862
+ */
863
+
864
+ var audioContext = {
865
+ /**
866
+ * @returns [AudioContext]
867
+ * Returns `null` if web audio API is not supported or creating
868
+ * the context fails.
869
+ */
870
+ get: function get() {
871
+ var AudioContext = window.AudioContext || window.webkitAudioContext;
872
+
873
+ if (typeof this._audioContext === 'undefined') {
874
+ try {
875
+ this._audioContext = AudioContext && new AudioContext();
876
+ } catch (e) {
877
+ this._audioContext = null;
878
+ log('Failed to create AudioContext.', {
879
+ force: true
880
+ });
881
+ }
882
+ }
883
+
884
+ return this._audioContext;
885
+ }
886
+ };
887
+
888
+ var webAudio = function webAudio(player, audioContext) {
889
+ var gainNode;
890
+ var currentResolve;
891
+ var currentTimeout;
892
+ var currentValue = 1;
893
+ var lastStartTime;
894
+ var lastDuration;
895
+ var lastStartValue;
896
+ var allowedMinValue = 0.000001;
897
+
898
+ if (audioContext.state === 'suspended') {
899
+ events.on('background_media:unmute', function () {
900
+ player.volume(currentValue);
901
+ });
902
+ }
903
+
904
+ function tryResumeIfSuspended() {
905
+ return new Promise(function (resolve, reject) {
906
+ if (audioContext.state === 'suspended') {
907
+ var maybePromise = audioContext.resume();
908
+
909
+ if (maybePromise && maybePromise.then) {
910
+ maybePromise.then(handlePromise);
911
+ } else {
912
+ setTimeout(handlePromise, 0);
913
+ }
914
+ } else {
915
+ resolve();
916
+ }
917
+
918
+ function handlePromise() {
919
+ if (audioContext.state === 'suspended') {
920
+ reject();
921
+ } else {
922
+ resolve();
923
+ }
924
+ }
925
+ });
926
+ }
927
+
928
+ player.volume = function (value) {
929
+ if (typeof value !== 'undefined') {
930
+ tryResumeIfSuspended().then(function () {
931
+ ensureGainNode();
932
+ cancel();
933
+ currentValue = ensureInAllowedRange(value);
934
+ gainNode.gain.setValueAtTime(currentValue, audioContext.currentTime);
935
+ }, function () {
936
+ currentValue = ensureInAllowedRange(value);
937
+ });
938
+ }
939
+
940
+ return Math.round(currentValue * 100) / 100;
941
+ };
942
+
943
+ player.fadeVolume = function (value, duration) {
944
+ return tryResumeIfSuspended().then(function () {
945
+ ensureGainNode();
946
+ cancel();
947
+ recordFadeStart(duration);
948
+ currentValue = ensureInAllowedRange(value);
949
+ gainNode.gain.setValueAtTime(lastStartValue, audioContext.currentTime);
950
+ gainNode.gain.linearRampToValueAtTime(currentValue, audioContext.currentTime + duration / 1000);
951
+ return new Promise(function (resolve, reject) {
952
+ currentResolve = resolve;
953
+ currentTimeout = setTimeout(resolveCurrent, duration);
954
+ });
955
+ }, function () {
956
+ currentValue = ensureInAllowedRange(value);
957
+ return Promise.resolve();
958
+ });
959
+ };
960
+
961
+ player.one('dispose', cancel);
962
+
963
+ function ensureGainNode() {
964
+ if (!gainNode) {
965
+ gainNode = audioContext.createGain();
966
+ var source = audioContext.createMediaElementSource(player.getMediaElement());
967
+ source.connect(gainNode);
968
+ gainNode.connect(audioContext.destination);
969
+ }
970
+ }
971
+
972
+ function resolveCurrent() {
973
+ clearTimeout(currentTimeout);
974
+ currentResolve('done');
975
+ currentTimeout = null;
976
+ currentResolve = null;
977
+ }
978
+
979
+ function cancel() {
980
+ if (currentResolve) {
981
+ gainNode.gain.cancelScheduledValues(audioContext.currentTime);
982
+ clearTimeout(currentTimeout);
983
+ currentResolve('cancelled');
984
+ currentTimeout = null;
985
+ currentResolve = null;
986
+ updateCurrentValueFromComputedValue();
987
+ }
988
+ }
989
+
990
+ function recordFadeStart(duration) {
991
+ lastStartTime = audioContext.currentTime;
992
+ lastStartValue = currentValue;
993
+ lastDuration = duration;
994
+ }
995
+
996
+ function updateCurrentValueFromComputedValue() {
997
+ // Firefox 54 on Ubuntu does not provide computed values when gain
998
+ // was changed via one of the scheduling methods. Instead
999
+ // gain.value always reports 1. Interpolate manually do determine
1000
+ // how far the fade was performed before cancel was called.
1001
+ if (gainNode.gain.value == 1) {
1002
+ var performedDuration = (audioContext.currentTime - lastStartTime) * 1000;
1003
+ var lastDelta = currentValue - lastStartValue;
1004
+ var performedFraction = lastDelta > 0 ? performedDuration / lastDuration : 1;
1005
+ currentValue = ensureInAllowedRange(lastStartValue + performedFraction * lastDelta);
1006
+ } else {
1007
+ currentValue = gainNode.gain.value;
1008
+ }
1009
+ }
1010
+
1011
+ function ensureInAllowedRange(value) {
1012
+ return value < allowedMinValue ? allowedMinValue : value;
1013
+ }
1014
+ };
1015
+
1016
+ var noop = function noop(player) {
1017
+ player.fadeVolume = function (value, duration) {
1018
+ return Promise.resolve();
1019
+ };
1020
+ };
1021
+
1022
+ var interval = function interval(player) {
1023
+ var originalVolume = player.volume;
1024
+ var fadeVolumeResolve;
1025
+ var fadeVolumeInterval;
1026
+
1027
+ player.volume = function (value) {
1028
+ if (typeof value !== 'undefined') {
1029
+ cancelFadeVolume();
1030
+ }
1031
+
1032
+ return originalVolume.apply(player, arguments);
1033
+ };
1034
+
1035
+ player.fadeVolume = function (value, duration) {
1036
+ cancelFadeVolume();
1037
+ return new Promise(function (resolve, reject) {
1038
+ var resolution = 10;
1039
+ var startValue = volume();
1040
+ var steps = duration / resolution;
1041
+ var leap = (value - startValue) / steps;
1042
+
1043
+ if (value === startValue) {
1044
+ resolve();
1045
+ } else {
1046
+ fadeVolumeResolve = resolve;
1047
+ fadeVolumeInterval = setInterval(function () {
1048
+ volume(volume() + leap);
1049
+
1050
+ if (volume() >= value && value >= startValue || volume() <= value && value <= startValue) {
1051
+ resolveFadeVolume();
1052
+ }
1053
+ }, resolution);
1054
+ }
1055
+ });
1056
+ };
1057
+
1058
+ player.one('dispose', cancelFadeVolume);
1059
+
1060
+ function volume()
1061
+ /* arguments */
1062
+ {
1063
+ return originalVolume.apply(player, arguments);
1064
+ }
1065
+
1066
+ function resolveFadeVolume() {
1067
+ clearInterval(fadeVolumeInterval);
1068
+ fadeVolumeResolve('done');
1069
+ fadeVolumeInterval = null;
1070
+ fadeVolumeResolve = null;
1071
+ }
1072
+
1073
+ function cancelFadeVolume() {
1074
+ if (fadeVolumeResolve) {
1075
+ fadeVolumeResolve('cancelled');
1076
+ fadeVolumeResolve = null;
1077
+ }
1078
+
1079
+ if (fadeVolumeInterval) {
1080
+ clearInterval(fadeVolumeInterval);
1081
+ fadeVolumeInterval = null;
1082
+ }
1083
+ }
1084
+ };
1085
+
1086
+ var volumeFading = function volumeFading(player) {
1087
+ if (!browser.has('volume control support')) {
1088
+ return noop(player);
1089
+ } else if (browser.has('audio context volume fading support') && audioContext.get() && player.getMediaElement) {
1090
+ return webAudio(player, audioContext.get());
1091
+ } else {
1092
+ return interval(player);
1093
+ }
1094
+ };
1095
+
1096
+ volumeFading.interval = interval;
1097
+ volumeFading.noop = noop;
1098
+ volumeFading.webAudio = webAudio;
1099
+
1100
+ var loadWaiting = function loadWaiting(player) {
1101
+ var originalFadeVolume = player.fadeVolume;
1102
+
1103
+ player.fadeVolume = function ()
1104
+ /* args */
1105
+ {
1106
+ var args = arguments;
1107
+ return Promise.all([this.loadedPromise]).then(function () {
1108
+ return originalFadeVolume.apply(player, args);
1109
+ });
1110
+ };
1111
+ };
1112
+
1113
+ var Settings =
1114
+ /*#__PURE__*/
1115
+ function () {
1116
+ function Settings() {
1117
+ _classCallCheck(this, Settings);
1118
+
1119
+ this.attributes = {
1120
+ volume: 1
1121
+ };
1122
+ this.initialize();
1123
+ }
1124
+
1125
+ _createClass(Settings, [{
1126
+ key: "get",
1127
+ value: function get(attributeName) {
1128
+ return this.attributes[attributeName];
1129
+ }
1130
+ }, {
1131
+ key: "set",
1132
+ value: function set(key, value) {
1133
+ var attrs;
1134
+
1135
+ if (typeof key === 'object') {
1136
+ attrs = key;
1137
+ } else {
1138
+ (attrs = {})[key] = value;
1139
+ }
1140
+
1141
+ for (var attr in attrs) {
1142
+ this.attributes[attr] = attrs[attr];
1143
+ this.trigger('change:' + attr);
1144
+ }
1145
+
1146
+ this.trigger('change');
1147
+ }
1148
+ }, {
1149
+ key: "toJSON",
1150
+ value: function toJSON() {
1151
+ return _objectSpread2({}, this.attributes);
1152
+ }
1153
+ }, {
1154
+ key: "initialize",
1155
+ value: function initialize() {
1156
+ var storage = this.getLocalStorage();
1157
+
1158
+ if (storage) {
1159
+ if (storage['pageflow.settings']) {
1160
+ try {
1161
+ this.set(JSON.parse(storage['pageflow.settings']));
1162
+ } catch (e) {
1163
+ log(e);
1164
+ }
1165
+ }
1166
+
1167
+ this.on('change', function () {
1168
+ storage['pageflow.settings'] = JSON.stringify(this.attributes);
1169
+ });
1170
+ }
1171
+ }
1172
+ }, {
1173
+ key: "getLocalStorage",
1174
+ value: function getLocalStorage() {
1175
+ try {
1176
+ return window.localStorage;
1177
+ } catch (e) {
1178
+ // Safari throws SecurityError when accessing window.localStorage
1179
+ // if cookies/website data are disabled.
1180
+ return null;
1181
+ }
1182
+ }
1183
+ }]);
1184
+
1185
+ return Settings;
1186
+ }();
1187
+
1188
+ Object.assign(Settings.prototype, BackboneEvents);
1189
+ var settings = new Settings();
1190
+
1191
+ var mediaPlayer = {
1192
+ enhance: function enhance(player, options) {
1193
+ handleFailedPlay(player, _objectSpread2({
1194
+ hasAutoplaySupport: browser.has('autoplay support')
1195
+ }, options));
1196
+ asyncPlay(player);
1197
+
1198
+ if (options.hooks) {
1199
+ hooks(player, options.hooks);
1200
+ }
1201
+
1202
+ if (options.volumeFading) {
1203
+ volumeFading(player);
1204
+ volumeBinding(player, settings, options);
1205
+ }
1206
+
1207
+ if (options.loadWaiting) {
1208
+ loadWaiting(player);
1209
+ }
1210
+ }
1211
+ };
1212
+
1213
+ mediaPlayer.handleFailedPlay = handleFailedPlay;
1214
+ mediaPlayer.volumeBinding = volumeBinding;
1215
+ mediaPlayer.volumeFading = volumeFading;
1216
+ mediaPlayer.loadWaiting = loadWaiting;
1217
+ mediaPlayer.hooks = hooks;
1218
+ mediaPlayer.asyncPlay = asyncPlay;
1219
+
1220
+ var mediaEvents = function mediaEvents(player, context) {
1221
+ function triggerMediaEvent(name) {
1222
+ events.trigger('media:' + name, {
1223
+ fileName: player.currentSrc,
1224
+ context: context,
1225
+ currentTime: player.position,
1226
+ duration: player.duration,
1227
+ volume: player.volume(),
1228
+ bitrate: 128000
1229
+ });
1230
+ }
1231
+
1232
+ player.on('play', function () {
1233
+ triggerMediaEvent('play');
1234
+ });
1235
+ player.on('timeupdate', function () {
1236
+ triggerMediaEvent('timeupdate');
1237
+ });
1238
+ player.on('pause', function () {
1239
+ triggerMediaEvent('pause');
1240
+ });
1241
+ player.on('ended', function () {
1242
+ triggerMediaEvent('ended');
1243
+ });
1244
+ };
1245
+
1246
+ // Prevent audio play back when browser enters background on mobile
1247
+ // device. Use the face that timeupdate events continue to fire while
1248
+ // intervals no longer executed when the browser is in the background.
1249
+ var pauseInBackground = function pauseInBackground(player) {
1250
+ var interval;
1251
+ var lastInterval;
1252
+ var resolution = 100;
1253
+
1254
+ function startProbeInterval() {
1255
+ interval = setInterval(function () {
1256
+ lastInterval = new Date().getTime();
1257
+ }, resolution);
1258
+ }
1259
+
1260
+ function stopProbeInterval() {
1261
+ clearInterval(interval);
1262
+ interval = null;
1263
+ }
1264
+
1265
+ function pauseIfProbeIntervalHalted() {
1266
+ if (intervalHalted()) {
1267
+ player.pause();
1268
+ }
1269
+ }
1270
+
1271
+ function intervalHalted() {
1272
+ return interval && lastInterval < new Date().getTime() - resolution * 5;
1273
+ }
1274
+
1275
+ player.on('play', startProbeInterval);
1276
+ player.on('pause', stopProbeInterval);
1277
+ player.on('ended', stopProbeInterval);
1278
+ player.on('timeupdate', pauseIfProbeIntervalHalted);
1279
+ };
1280
+
1281
+ /**
1282
+ * Calling seek before the media tag is ready causes InvalidState
1283
+ * exeption. If this happens, we wait for the next progress event and
1284
+ * retry. We resolve a promise once seeking succeeded.
1285
+ *
1286
+ * @api private
1287
+ */
1288
+ var seekWithInvalidStateHandling = function seekWithInvalidStateHandling(player) {
1289
+ var originalSeek = player.seek;
1290
+
1291
+ player.seek = function (time) {
1292
+ return retryOnProgress(function () {
1293
+ originalSeek.call(player, time);
1294
+ });
1295
+ };
1296
+
1297
+ function retryOnProgress(fn) {
1298
+ var tries = 0;
1299
+ return new Promise(function (resolve, reject) {
1300
+ function tryOrWaitForProgress() {
1301
+ tries += 1;
1302
+
1303
+ if (tries >= 50) {
1304
+ reject();
1305
+ return;
1306
+ }
1307
+
1308
+ try {
1309
+ fn();
1310
+ resolve();
1311
+ } catch (e) {
1312
+ player.one('progress', tryOrWaitForProgress);
1313
+ }
1314
+ }
1315
+
1316
+ tryOrWaitForProgress();
1317
+ });
1318
+ }
1319
+ };
1320
+
1321
+ var rewindMethod = function rewindMethod(player) {
1322
+ /**
1323
+ * Seek to beginning of file. If already at the beginning do
1324
+ * nothing.
1325
+ *
1326
+ * @alias pageflow.AudioPlayer#rewind
1327
+ */
1328
+ player.rewind = function () {
1329
+ if (player.position > 0) {
1330
+ var result = player.seek(0);
1331
+ player.trigger('timeupdate', player.position, player.duration);
1332
+ return result;
1333
+ } else {
1334
+ return Promise.resolve();
1335
+ }
1336
+ };
1337
+ };
1338
+
1339
+ var getMediaElementMethod = function getMediaElementMethod(player) {
1340
+ player.getMediaElement = function () {
1341
+ return player.audio.audio;
1342
+ };
1343
+ };
1344
+
1345
+ /**
1346
+ * Playing audio sources
1347
+ *
1348
+ * @param {Object[]} sources
1349
+ * List of sources for audio element.
1350
+ *
1351
+ * @param {string} sources[].type
1352
+ * Mime type of the audio.
1353
+ *
1354
+ * @param {string} sources[].src
1355
+ * Url of the audio.
1356
+ *
1357
+ * @class
1358
+ */
1359
+
1360
+ var AudioPlayer = function AudioPlayer(sources, options) {
1361
+ options = options || {};
1362
+ var codecMapping = {
1363
+ vorbis: 'audio/ogg',
1364
+ mp4: 'audio/mp4',
1365
+ mp3: 'audio/mpeg'
1366
+ };
1367
+ var readyResolve;
1368
+ var readyPromise = new Promise(function (resolve) {
1369
+ readyResolve = resolve;
1370
+ });
1371
+ var loadedResolve;
1372
+ var loadedPromise = new Promise(function (resolve) {
1373
+ loadedResolve = resolve;
1374
+ });
1375
+ var audio = new Audio5js({
1376
+ reusedTag: options.tag,
1377
+ swf_path: assetUrls.audioSwf,
1378
+ throw_errors: false,
1379
+ format_time: false,
1380
+ codecs: options.codecs || ['vorbis', 'mp4', 'mp3'],
1381
+ ready: readyResolve,
1382
+ loop: options.loop
1383
+ });
1384
+ audio.readyPromise = readyPromise;
1385
+ audio.loadedPromise = loadedPromise;
1386
+ audio.on('load', loadedResolve);
1387
+
1388
+ if (options.mediaEvents) {
1389
+ mediaEvents(audio, options.context);
1390
+ }
1391
+
1392
+ if (options.pauseInBackground && browser.has('mobile platform')) {
1393
+ pauseInBackground(audio);
1394
+ }
1395
+
1396
+ mediaPlayer.enhance(audio, _objectSpread2({
1397
+ loadWaiting: true
1398
+ }, options));
1399
+ seekWithInvalidStateHandling(audio);
1400
+ rewindMethod(audio);
1401
+ getMediaElementMethod(audio);
1402
+
1403
+ audio.src = function (sources) {
1404
+ readyPromise.then(function () {
1405
+ var source = (sources || []).find(function (source) {
1406
+ return codecMapping[audio.settings.player.codec] === source.type;
1407
+ });
1408
+ audio.load(source ? source.src : '');
1409
+ });
1410
+ };
1411
+
1412
+ var originalLoad = audio.load;
1413
+
1414
+ audio.load = function (src) {
1415
+ if (!src) {
1416
+ this.duration = 0;
1417
+ }
1418
+
1419
+ this.currentSrc = src;
1420
+ this.position = 0;
1421
+ this.trigger('timeupdate', this.position, this.duration);
1422
+ originalLoad.apply(this, arguments);
1423
+ };
1424
+
1425
+ var originalSeek = audio.seek;
1426
+
1427
+ audio.seek = function () {
1428
+ if (this.currentSrc) {
1429
+ return originalSeek.apply(this, arguments);
1430
+ }
1431
+ };
1432
+
1433
+ var originalPlay = audio.play;
1434
+
1435
+ audio.play = function () {
1436
+ if (this.currentSrc) {
1437
+ originalPlay.apply(this, arguments);
1438
+ }
1439
+ };
1440
+
1441
+ audio.paused = function () {
1442
+ return !audio.playing;
1443
+ };
1444
+
1445
+ audio.src(sources);
1446
+ return audio;
1447
+ };
1448
+
1449
+ AudioPlayer.fromAudioTag = function (element, options) {
1450
+ return new AudioPlayer(element.find('source').map(function () {
1451
+ return {
1452
+ src: this.getAttribute('src'),
1453
+ type: this.getAttribute('type')
1454
+ };
1455
+ }).get(), _objectSpread2({
1456
+ tag: element[0]
1457
+ }, options));
1458
+ };
1459
+
1460
+ AudioPlayer.fromScriptTag = function (element, options) {
1461
+ var sources = element.length ? JSON.parse(element.text()) : [];
1462
+ return new AudioPlayer(sources, options);
1463
+ };
1464
+
1465
+ var Null = function Null() {
1466
+ this.playAndFadeIn = function () {
1467
+ return Promise.resolve();
1468
+ };
1469
+
1470
+ this.fadeOutAndPause = function () {
1471
+ return Promise.resolve();
1472
+ };
1473
+
1474
+ this.changeVolumeFactor = function () {
1475
+ return Promise.resolve();
1476
+ };
1477
+
1478
+ this.play = function () {};
1479
+
1480
+ this.pause = function () {};
1481
+
1482
+ this.paused = function () {
1483
+ return true;
1484
+ };
1485
+
1486
+ this.seek = function () {
1487
+ return Promise.resolve();
1488
+ };
1489
+
1490
+ this.rewind = function () {
1491
+ return Promise.resolve();
1492
+ };
1493
+
1494
+ this.formatTime = function () {};
1495
+
1496
+ this.one = function (event, handler) {
1497
+ handler();
1498
+ };
1499
+ };
1500
+ Object.assign(Null.prototype, BackboneEvents);
1501
+
1502
+ AudioPlayer.mediaEvents = mediaEvents;
1503
+ AudioPlayer.Null = Null;
1504
+ AudioPlayer.seekWithInvalidStateHandling = seekWithInvalidStateHandling;
1505
+ AudioPlayer.rewindMethod = rewindMethod;
1506
+ AudioPlayer.pauseInBackground = pauseInBackground;
1507
+
1508
+ function _arrayLikeToArray(arr, len) {
1509
+ if (len == null || len > arr.length) len = arr.length;
1510
+
1511
+ for (var i = 0, arr2 = new Array(len); i < len; i++) {
1512
+ arr2[i] = arr[i];
1513
+ }
1514
+
1515
+ return arr2;
1516
+ }
1517
+
1518
+ function _arrayWithoutHoles(arr) {
1519
+ if (Array.isArray(arr)) return _arrayLikeToArray(arr);
1520
+ }
1521
+
1522
+ function _iterableToArray(iter) {
1523
+ if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
1524
+ }
1525
+
1526
+ function _unsupportedIterableToArray(o, minLen) {
1527
+ if (!o) return;
1528
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
1529
+ var n = Object.prototype.toString.call(o).slice(8, -1);
1530
+ if (n === "Object" && o.constructor) n = o.constructor.name;
1531
+ if (n === "Map" || n === "Set") return Array.from(n);
1532
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
1533
+ }
1534
+
1535
+ function _nonIterableSpread() {
1536
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1537
+ }
1538
+
1539
+ function _toConsumableArray(arr) {
1540
+ return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
1541
+ }
1542
+
1543
+ var filterSources = function filterSources(playerElement) {
1544
+ if (playerElement.tagName.toLowerCase() !== 'video') {
1545
+ return playerElement;
1546
+ }
1547
+
1548
+ var changed = false;
1549
+
1550
+ if (browser.has('mp4 support only')) {
1551
+ // keep only mp4 source
1552
+ playerElement.querySelectorAll('source').forEach(function (source) {
1553
+ if (source.type !== 'video/mp4') {
1554
+ playerElement.removeChild(source);
1555
+ }
1556
+ });
1557
+ changed = true;
1558
+ } else if (browser.has('mse and native hls support')) {
1559
+ // remove dash source to ensure hls is used
1560
+ var dashSource = playerElement.querySelector('source[type="application/dash+xml"]');
1561
+
1562
+ if (dashSource) {
1563
+ playerElement.removeChild(dashSource);
1564
+ changed = true;
1565
+ }
1566
+ }
1567
+
1568
+ if (changed) {
1569
+ // the video tags initially in the dom are broken since they "saw"
1570
+ // the other sources. replace with clone
1571
+ var clone = playerElement.cloneNode(true);
1572
+ playerElement.replaceWith(clone);
1573
+ return clone;
1574
+ } else {
1575
+ return playerElement;
1576
+ }
1577
+ };
1578
+
1579
+ var useSlimPlayerControlsDuringPhonePlayback = function useSlimPlayerControlsDuringPhonePlayback(player) {
1580
+ var originalPlay = player.play;
1581
+
1582
+ player.play = function () {
1583
+ if (browser.has('phone platform') && !browser.has('native video player')) {
1584
+ state.widgets.use({
1585
+ name: 'slim_player_controls',
1586
+ insteadOf: 'classic_player_controls'
1587
+ }, function (restoreWidgets) {
1588
+ player.one('pause', restoreWidgets);
1589
+ });
1590
+ }
1591
+
1592
+ return originalPlay.apply(this, arguments);
1593
+ };
1594
+ };
1595
+
1596
+ var prebuffering = function prebuffering(player) {
1597
+ var prebufferPromiseReject;
1598
+
1599
+ player.isBufferedAhead = function (delta, silent) {
1600
+ // video.js only gives us one time range starting from 0 here. We
1601
+ // still ask for the last time range to be on the safe side.
1602
+ var timeRanges = player.buffered();
1603
+ var currentBufferTime = timeRanges.end(timeRanges.length - 1);
1604
+ var desiredBufferTime = player.currentTime() + delta;
1605
+
1606
+ if (player.duration()) {
1607
+ desiredBufferTime = Math.min(desiredBufferTime, Math.floor(player.duration()));
1608
+ }
1609
+
1610
+ var result = currentBufferTime >= desiredBufferTime;
1611
+
1612
+ if (!silent) {
1613
+ log('buffered ahead ' + delta + ': ' + result + ' (' + currentBufferTime + '/' + desiredBufferTime + ')');
1614
+ }
1615
+
1616
+ return result;
1617
+ };
1618
+
1619
+ player.prebuffer = function (options) {
1620
+ options = options || {};
1621
+ var delta = options.secondsToBuffer || 10;
1622
+ var secondsToWait = options.secondsToWait || 3;
1623
+ var interval = 200;
1624
+ var maxCount = secondsToWait * 1000 / interval;
1625
+ var count = 0;
1626
+
1627
+ if (browser.has('prebuffering support')) {
1628
+ if (!player.isBufferedAhead(delta) && !player.prebufferPromise) {
1629
+ log('prebuffering video ' + player.src());
1630
+ player.prebufferPromise = new Promise(function (resolve, reject) {
1631
+ prebufferPromiseReject = reject;
1632
+ wait();
1633
+
1634
+ function wait() {
1635
+ setTimeout(function () {
1636
+ if (!player.prebufferPromise) {
1637
+ return;
1638
+ }
1639
+
1640
+ count++;
1641
+
1642
+ if (player.isBufferedAhead(delta) || count > maxCount) {
1643
+ log('finished prebuffering video ' + player.src());
1644
+ resolve();
1645
+ player.prebufferPromise = null;
1646
+ } else {
1647
+ wait();
1648
+ }
1649
+ }, interval);
1650
+ }
1651
+ });
1652
+ }
1653
+ }
1654
+
1655
+ return player.prebufferPromise ? player.prebufferPromise : Promise.resolve();
1656
+ };
1657
+
1658
+ player.abortPrebuffering = function () {
1659
+ if (player.prebufferPromise) {
1660
+ log('ABORT prebuffering');
1661
+ prebufferPromiseReject('prebuffering aborted');
1662
+ player.prebufferPromise = null;
1663
+ }
1664
+ };
1665
+
1666
+ var originalPause = player.pause;
1667
+
1668
+ player.pause = function () {
1669
+ player.abortPrebuffering();
1670
+ return originalPause.apply(this, arguments);
1671
+ };
1672
+
1673
+ player.one('dispose', function () {
1674
+ player.abortPrebuffering();
1675
+ });
1676
+ };
1677
+
1678
+ var cueSettingsMethods = function cueSettingsMethods(player) {
1679
+ /**
1680
+ * Specify the display position of text tracks. This method can also
1681
+ * be used to make VideoJS reposition the text tracks after the
1682
+ * margins of the text track display have been changed (e.g. to
1683
+ * translate text tracks when player controls are displayed).
1684
+ *
1685
+ * To force such an update, the passed string has to differ from the
1686
+ * previously passed string. You can append a dot and an arbitrary
1687
+ * string (e.g. `"auto.translated"`), to keep the current setting but
1688
+ * still force repositioning.
1689
+ *
1690
+ * On the other hand, it is possible to change the positioning but
1691
+ * have VideoJS apply the change only when the next cue is
1692
+ * displayed. This way we can prevent moving a cue that the user
1693
+ * might just be reading. Simply append the string `".lazy"`
1694
+ * (e.g. `"auto.lazy"`).
1695
+ *
1696
+ * @param {string} line
1697
+ * Either `"top"` to move text tracks to the first line or
1698
+ * `"auto"` to stick with automatic positioning, followed by a tag
1699
+ * to either force or prevent immediate update.
1700
+ */
1701
+ player.updateCueLineSettings = function (line) {
1702
+ var components = line.split('.');
1703
+ var value = components[0];
1704
+ var command = components[1];
1705
+ value = value == 'top' ? 1 : value;
1706
+ var changed = false;
1707
+ Array.from(player.textTracks()).forEach(function (textTrack) {
1708
+ if (textTrack.mode == 'showing' && textTrack.cues) {
1709
+ for (var i = 0; i < textTrack.cues.length; i++) {
1710
+ if (textTrack.cues[i].line != value) {
1711
+ textTrack.cues[i].line = value;
1712
+ changed = true;
1713
+ }
1714
+ }
1715
+ }
1716
+ }); // Setting `line` does not update display directly, but only when
1717
+ // the next cue is displayed. This is problematic, when we
1718
+ // reposition text tracks to prevent overlap with player
1719
+ // controls. Triggering the event makes VideoJS update positions.
1720
+ // Ensure display is also updated when the current showing text
1721
+ // track changed since the last call, i.e. `line` has been changed
1722
+ // for a cue even though the previous call had the same
1723
+ // parameters.
1724
+
1725
+ if ((this.prevLine !== line || changed) && command != 'lazy') {
1726
+ var tech = player.tech({
1727
+ IWillNotUseThisInPlugins: true
1728
+ });
1729
+ tech && tech.trigger('texttrackchange');
1730
+ }
1731
+
1732
+ this.prevLine = line;
1733
+ };
1734
+ };
1735
+
1736
+ var getMediaElementMethod$1 = function getMediaElementMethod(player) {
1737
+ player.getMediaElement = function () {
1738
+ var tech = player.tech({
1739
+ IWillNotUseThisInPlugins: true
1740
+ });
1741
+ return tech && tech.el();
1742
+ };
1743
+ };
1744
+
1745
+ var mediaEvents$1 = function mediaEvents(player, context) {
1746
+ player.updateMediaEventsContext = function (newContext) {
1747
+ context = newContext;
1748
+ };
1749
+
1750
+ function triggerMediaEvent(name) {
1751
+ if (context) {
1752
+ events.trigger('media:' + name, {
1753
+ fileName: player.currentSrc(),
1754
+ context: context,
1755
+ currentTime: player.currentTime(),
1756
+ duration: player.duration(),
1757
+ volume: player.volume(),
1758
+ bitrate: 3500000
1759
+ });
1760
+ }
1761
+ }
1762
+
1763
+ player.on('play', function () {
1764
+ triggerMediaEvent('play');
1765
+ });
1766
+ player.on('timeupdate', function () {
1767
+ triggerMediaEvent('timeupdate');
1768
+ });
1769
+ player.on('pause', function () {
1770
+ triggerMediaEvent('pause');
1771
+ });
1772
+ player.on('ended', function () {
1773
+ triggerMediaEvent('ended');
1774
+ });
1775
+ };
1776
+
1777
+ var bufferUnderrunWaiting = function bufferUnderrunWaiting(player) {
1778
+ var originalPause = player.pause;
1779
+
1780
+ player.pause = function () {
1781
+ cancelWaiting();
1782
+ originalPause.apply(this, arguments);
1783
+ };
1784
+
1785
+ function pauseAndPreloadOnUnderrun() {
1786
+ if (bufferUnderrun()) {
1787
+ pauseAndPreload();
1788
+ }
1789
+ }
1790
+
1791
+ function bufferUnderrun() {
1792
+ return !player.isBufferedAhead(0.1, true) && !player.waitingOnUnderrun && !ignoringUnderruns();
1793
+ }
1794
+
1795
+ function pauseAndPreload() {
1796
+ log('Buffer underrun');
1797
+ player.trigger('bufferunderrun');
1798
+ player.pause();
1799
+ player.waitingOnUnderrun = true;
1800
+ player.prebuffer({
1801
+ secondsToBuffer: 5,
1802
+ secondsToWait: 5
1803
+ }).then(function () {
1804
+ // do nothing if user aborted waiting by clicking pause
1805
+ if (player.waitingOnUnderrun) {
1806
+ player.waitingOnUnderrun = false;
1807
+ player.trigger('bufferunderruncontinue');
1808
+ player.play();
1809
+ }
1810
+ }, function () {});
1811
+ }
1812
+
1813
+ function cancelWaiting() {
1814
+ if (player.waitingOnUnderrun) {
1815
+ player.ignoreUnderrunsUntil = new Date().getTime() + 5 * 1000;
1816
+ player.waitingOnUnderrun = false;
1817
+ player.trigger('bufferunderruncontinue');
1818
+ }
1819
+ }
1820
+
1821
+ function ignoringUnderruns() {
1822
+ var r = player.ignoreUnderrunsUntil && new Date().getTime() < player.ignoreUnderrunsUntil;
1823
+
1824
+ if (r) {
1825
+ log('ignoring underrun');
1826
+ }
1827
+
1828
+ return r;
1829
+ }
1830
+
1831
+ function stopListeningForProgress() {
1832
+ player.off('progress', pauseAndPreloadOnUnderrun);
1833
+ }
1834
+
1835
+ if (browser.has('buffer underrun waiting support')) {
1836
+ player.on('play', function () {
1837
+ player.on('progress', pauseAndPreloadOnUnderrun);
1838
+ });
1839
+ player.on('pause', stopListeningForProgress);
1840
+ player.on('ended', stopListeningForProgress);
1841
+ }
1842
+ };
1843
+
1844
+ var rewindMethod$1 = function rewindMethod(player) {
1845
+ /**
1846
+ * Seek to beginning of file. If already at the beginning do
1847
+ * nothing.
1848
+ *
1849
+ * @alias pageflow.VideoPlayer#rewind
1850
+ */
1851
+ player.rewind = function () {
1852
+ if (player.currentTime() > 0) {
1853
+ player.currentTime(0);
1854
+ player.trigger('timeupdate', player.currentTime(), player.duration());
1855
+ return Promise.resolve();
1856
+ } else {
1857
+ return Promise.resolve();
1858
+ }
1859
+ };
1860
+ };
1861
+
1862
+ var VideoPlayer = function VideoPlayer(element, options) {
1863
+ options = options || {};
1864
+ element = filterSources(element);
1865
+ var player = VideoJS(element, options);
1866
+
1867
+ if (options.useSlimPlayerControlsDuringPhonePlayback) {
1868
+ useSlimPlayerControlsDuringPhonePlayback(player);
1869
+ }
1870
+
1871
+ prebuffering(player);
1872
+ cueSettingsMethods(player);
1873
+ getMediaElementMethod$1(player);
1874
+ rewindMethod$1(player);
1875
+
1876
+ if (options.mediaEvents) {
1877
+ mediaEvents$1(player, options.context);
1878
+ }
1879
+
1880
+ if (options.bufferUnderrunWaiting) {
1881
+ bufferUnderrunWaiting(player);
1882
+ }
1883
+
1884
+ mediaPlayer.enhance(player, options);
1885
+ return player;
1886
+ };
1887
+
1888
+ if (VideoJS.Html5DashJS) {
1889
+ VideoJS.Html5DashJS.hook('beforeinitialize', function (player, mediaPlayer) {
1890
+ mediaPlayer.getDebug().setLogToBrowserConsole(false);
1891
+ });
1892
+ }
1893
+
1894
+ VideoPlayer.useSlimPlayerControlsDuringPhonePlayback = useSlimPlayerControlsDuringPhonePlayback;
1895
+ VideoPlayer.prebuffering = prebuffering;
1896
+ VideoPlayer.filterSources = filterSources;
1897
+ VideoPlayer.mediaEvents = mediaEvents$1;
1898
+ VideoPlayer.cueSettingsMethods = cueSettingsMethods;
1899
+ VideoPlayer.bufferUnderrunWaiting = bufferUnderrunWaiting;
1900
+
1901
+ var createMediaPlayer = function createMediaPlayer(options) {
1902
+ var isAudio = options.tagName == 'AUDIO';
1903
+ var player = new VideoPlayer(options.mediaElement, {
1904
+ controlBar: false,
1905
+ loadingSpinner: false,
1906
+ bigPlayButton: false,
1907
+ errorDisplay: false,
1908
+ textTrackSettings: false,
1909
+ poster: options.poster,
1910
+ loop: options.loop,
1911
+ controls: options.controls,
1912
+ html5: {
1913
+ nativeCaptions: !isAudio && browser.has('iphone platform')
1914
+ },
1915
+ bufferUnderrunWaiting: true,
1916
+ fallbackToMutedAutoplay: !isAudio,
1917
+ volumeFading: true,
1918
+ hooks: {},
1919
+ mediaEvents: true,
1920
+ context: null
1921
+ });
1922
+ player.textTrackSettings = {
1923
+ getValues: function getValues() {
1924
+ return {};
1925
+ }
1926
+ };
1927
+
1928
+ player.playOrPlayOnLoad = function () {
1929
+ if (this.readyState() > 0) {
1930
+ player.play();
1931
+ } else {
1932
+ player.on('loadedmetadata', player.play);
1933
+ }
1934
+ };
1935
+
1936
+ player.addClass('video-js');
1937
+ player.addClass('player');
1938
+ return player;
1939
+ };
1940
+
1941
+ /**
1942
+ * Copyright 2017 The AMP HTML Authors. All Rights Reserved.
1943
+ *
1944
+ * Licensed under the Apache License, Version 2.0 (the "License");
1945
+ * you may not use this file except in compliance with the License.
1946
+ * You may obtain a copy of the License at
1947
+ *
1948
+ * http://www.apache.org/licenses/LICENSE-2.0
1949
+ *
1950
+ * Unless required by applicable law or agreed to in writing, software
1951
+ * distributed under the License is distributed on an "AS-IS" BASIS,
1952
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1953
+ * See the License for the specific language governing permissions and
1954
+ * limitations under the License.
1955
+ */
1956
+ var BLANK_AUDIO_SRC = 'data:audio/wav;base64,UklGRjIAAABXQVZFZm10IBA' + 'AAAABAAEAIlYAAESsAAACABAAZGF0YRAAAAAAAAAAAAAAAAAAAAAAAA==';
1957
+ var BLANK_VIDEO_SRC = 'data:video/mp4;base64,AAAAHGZ0eXBNNFYgAAACAG' + 'lzb21pc28yYXZjMQAAAAhmcmVlAAAGF21kYXTeBAAAbGliZmFhYyAxLjI4AABCAJMgBDIARw' + 'AAArEGBf//rdxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxNDIgcjIgOTU2YzhkOCAtIE' + 'guMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMTQgLSBodHRwOi8vd3' + 'd3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0wIHJlZj0zIGRlYm' + 'xvY2s9MTowOjAgYW5hbHlzZT0weDE6MHgxMTEgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3' + 'JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbG' + 'lzPTEgOHg4ZGN0PTAgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV' + '9xcF9vZmZzZXQ9LTIgdGhyZWFkcz02IGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3Rocm' + 'VhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb2' + '5zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MCB3ZWlnaHRwPTAga2V5aW50PTI1MCBrZXlpbn' + 'RfbWluPTI1IHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcm' + 'M9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcH' + 'N0ZXA9NCB2YnZfbWF4cmF0ZT03NjggdmJ2X2J1ZnNpemU9MzAwMCBjcmZfbWF4PTAuMCBuYW' + 'xfaHJkPW5vbmUgZmlsbGVyPTAgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAAFZliIQL8m' + 'KAAKvMnJycnJycnJycnXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXiEASZACGQAjgCEASZACGQAjgAAAAAdBmjgX4G' + 'SAIQBJkAIZACOAAAAAB0GaVAX4GSAhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZpgL8DJIQBJkA' + 'IZACOAIQBJkAIZACOAAAAABkGagC/AySEASZACGQAjgAAAAAZBmqAvwMkhAEmQAhkAI4AhAE' + 'mQAhkAI4AAAAAGQZrAL8DJIQBJkAIZACOAAAAABkGa4C/AySEASZACGQAjgCEASZACGQAjgA' + 'AAAAZBmwAvwMkhAEmQAhkAI4AAAAAGQZsgL8DJIQBJkAIZACOAIQBJkAIZACOAAAAABkGbQC' + '/AySEASZACGQAjgCEASZACGQAjgAAAAAZBm2AvwMkhAEmQAhkAI4AAAAAGQZuAL8DJIQBJkA' + 'IZACOAIQBJkAIZACOAAAAABkGboC/AySEASZACGQAjgAAAAAZBm8AvwMkhAEmQAhkAI4AhAE' + 'mQAhkAI4AAAAAGQZvgL8DJIQBJkAIZACOAAAAABkGaAC/AySEASZACGQAjgCEASZACGQAjgA' + 'AAAAZBmiAvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZpAL8DJIQBJkAIZACOAAAAABkGaYC' + '/AySEASZACGQAjgCEASZACGQAjgAAAAAZBmoAvwMkhAEmQAhkAI4AAAAAGQZqgL8DJIQBJkA' + 'IZACOAIQBJkAIZACOAAAAABkGawC/AySEASZACGQAjgAAAAAZBmuAvwMkhAEmQAhkAI4AhAE' + 'mQAhkAI4AAAAAGQZsAL8DJIQBJkAIZACOAAAAABkGbIC/AySEASZACGQAjgCEASZACGQAjgA' + 'AAAAZBm0AvwMkhAEmQAhkAI4AhAEmQAhkAI4AAAAAGQZtgL8DJIQBJkAIZACOAAAAABkGbgC' + 'vAySEASZACGQAjgCEASZACGQAjgAAAAAZBm6AnwMkhAEmQAhkAI4AhAEmQAhkAI4AhAEmQAh' + 'kAI4AhAEmQAhkAI4AAAAhubW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAABDcAAQAAAQ' + 'AAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAA' + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAzB0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAA' + 'AAAAAAA+kAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAA' + 'BAAAAAALAAAACQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAPpAAAAAAABAAAAAAKobW' + 'RpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAB1MAAAdU5VxAAAAAAALWhkbHIAAAAAAAAAAHZpZG' + 'UAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAACU21pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAA' + 'AAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAhNzdGJsAAAAr3N0c2QAAA' + 'AAAAAAAQAAAJ9hdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAALAAkABIAAAASAAAAAAAAA' + 'ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGP//AAAALWF2Y0MBQsAN/+EAFW' + 'dCwA3ZAsTsBEAAAPpAADqYA8UKkgEABWjLg8sgAAAAHHV1aWRraEDyXyRPxbo5pRvPAyPzAA' + 'AAAAAAABhzdHRzAAAAAAAAAAEAAAAeAAAD6QAAABRzdHNzAAAAAAAAAAEAAAABAAAAHHN0c2' + 'MAAAAAAAAAAQAAAAEAAAABAAAAAQAAAIxzdHN6AAAAAAAAAAAAAAAeAAADDwAAAAsAAAALAA' + 'AACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAA' + 'oAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAA' + 'AAiHN0Y28AAAAAAAAAHgAAAEYAAANnAAADewAAA5gAAAO0AAADxwAAA+MAAAP2AAAEEgAABC' + 'UAAARBAAAEXQAABHAAAASMAAAEnwAABLsAAATOAAAE6gAABQYAAAUZAAAFNQAABUgAAAVkAA' + 'AFdwAABZMAAAWmAAAFwgAABd4AAAXxAAAGDQAABGh0cmFrAAAAXHRraGQAAAADAAAAAAAAAA' + 'AAAAACAAAAAAAABDcAAAAAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAA' + 'AAAAAAAABAAAAAAAAAAAAAAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAQkAAADcAABAA' + 'AAAAPgbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAC7gAAAykBVxAAAAAAALWhkbHIAAAAAAA' + 'AAAHNvdW4AAAAAAAAAAAAAAABTb3VuZEhhbmRsZXIAAAADi21pbmYAAAAQc21oZAAAAAAAAA' + 'AAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAADT3N0YmwAAABnc3RzZA' + 'AAAAAAAAABAAAAV21wNGEAAAAAAAAAAQAAAAAAAAAAAAIAEAAAAAC7gAAAAAAAM2VzZHMAAA' + 'AAA4CAgCIAAgAEgICAFEAVBbjYAAu4AAAADcoFgICAAhGQBoCAgAECAAAAIHN0dHMAAAAAAA' + 'AAAgAAADIAAAQAAAAAAQAAAkAAAAFUc3RzYwAAAAAAAAAbAAAAAQAAAAEAAAABAAAAAgAAAA' + 'IAAAABAAAAAwAAAAEAAAABAAAABAAAAAIAAAABAAAABgAAAAEAAAABAAAABwAAAAIAAAABAA' + 'AACAAAAAEAAAABAAAACQAAAAIAAAABAAAACgAAAAEAAAABAAAACwAAAAIAAAABAAAADQAAAA' + 'EAAAABAAAADgAAAAIAAAABAAAADwAAAAEAAAABAAAAEAAAAAIAAAABAAAAEQAAAAEAAAABAA' + 'AAEgAAAAIAAAABAAAAFAAAAAEAAAABAAAAFQAAAAIAAAABAAAAFgAAAAEAAAABAAAAFwAAAA' + 'IAAAABAAAAGAAAAAEAAAABAAAAGQAAAAIAAAABAAAAGgAAAAEAAAABAAAAGwAAAAIAAAABAA' + 'AAHQAAAAEAAAABAAAAHgAAAAIAAAABAAAAHwAAAAQAAAABAAAA4HN0c3oAAAAAAAAAAAAAAD' + 'MAAAAaAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAA' + 'AACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAA' + 'kAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAA' + 'AACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAAAJAAAACQAAAAkAAACMc3RjbwAAAA' + 'AAAAAfAAAALAAAA1UAAANyAAADhgAAA6IAAAO+AAAD0QAAA+0AAAQAAAAEHAAABC8AAARLAA' + 'AEZwAABHoAAASWAAAEqQAABMUAAATYAAAE9AAABRAAAAUjAAAFPwAABVIAAAVuAAAFgQAABZ' + '0AAAWwAAAFzAAABegAAAX7AAAGFwAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAA' + 'AAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYX' + 'ZmNTUuMzMuMTAw';
1958
+ var blankSources = {
1959
+ 'audio': BLANK_AUDIO_SRC,
1960
+ 'video': BLANK_VIDEO_SRC
1961
+ };
1962
+
1963
+ /** @const @enum {string} */
1964
+
1965
+ var MediaType = {
1966
+ AUDIO: 'audio',
1967
+ VIDEO: 'video'
1968
+ };
1969
+ var elId = 0;
1970
+ /**
1971
+ * Media pool class handles the pool of Videojs media players
1972
+ */
1973
+
1974
+ var MediaPool =
1975
+ /*#__PURE__*/
1976
+ function () {
1977
+ function MediaPool() {
1978
+ var _this$mediaFactory_;
1979
+
1980
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
1981
+ playerCount: 4
1982
+ };
1983
+
1984
+ _classCallCheck(this, MediaPool);
1985
+
1986
+ this.playerCount = options.playerCount;
1987
+ this.allocatedPlayers = {};
1988
+ this.unAllocatedPlayers = {};
1989
+ this.mediaFactory_ = (_this$mediaFactory_ = {}, _defineProperty(_this$mediaFactory_, MediaType.AUDIO, function () {
1990
+ var audioEl = document.createElement('audio');
1991
+ audioEl.setAttribute('crossorigin', 'anonymous');
1992
+ return audioEl;
1993
+ }), _defineProperty(_this$mediaFactory_, MediaType.VIDEO, function () {
1994
+ var videoEl = document.createElement('video');
1995
+ videoEl.setAttribute('crossorigin', 'anonymous');
1996
+ return videoEl;
1997
+ }), _this$mediaFactory_);
1998
+ }
1999
+
2000
+ _createClass(MediaPool, [{
2001
+ key: "allocatePlayer",
2002
+ value: function allocatePlayer(_ref) {
2003
+ var playerType = _ref.playerType,
2004
+ playerId = _ref.playerId,
2005
+ playsInline = _ref.playsInline,
2006
+ mediaEventsContextData = _ref.mediaEventsContextData,
2007
+ hooks = _ref.hooks,
2008
+ poster = _ref.poster,
2009
+ _ref$loop = _ref.loop,
2010
+ loop = _ref$loop === void 0 ? false : _ref$loop,
2011
+ _ref$controls = _ref.controls,
2012
+ controls = _ref$controls === void 0 ? false : _ref$controls;
2013
+ var player = undefined;
2014
+
2015
+ if (!this.unAllocatedPlayers[playerType]) {
2016
+ this.populateMediaPool_();
2017
+ }
2018
+
2019
+ if (this.unAllocatedPlayers[playerType].length == 0) {
2020
+ this.freeOnePlayer(playerType);
2021
+ }
2022
+
2023
+ player = this.unAllocatedPlayers[playerType].pop();
2024
+
2025
+ if (player) {
2026
+ player.pause();
2027
+ player.getMediaElement().loop = loop;
2028
+ player.poster(poster);
2029
+ player.controls(controls);
2030
+
2031
+ if (playsInline) {
2032
+ player.playsinline(true);
2033
+ }
2034
+
2035
+ player.updateHooks(hooks || {});
2036
+ player.updateMediaEventsContext(mediaEventsContextData);
2037
+ this.allocatedPlayers[playerType].push(player);
2038
+ player.playerId = playerId || this.allocatedPlayers[playerType].length;
2039
+ return player;
2040
+ } else {
2041
+ console.log('no player found for allocation');
2042
+ }
2043
+ }
2044
+ }, {
2045
+ key: "freeOnePlayer",
2046
+ value: function freeOnePlayer(type) {
2047
+ this.unAllocatePlayer(this.allocatedPlayers[type][0]); // free up the first allocated player
2048
+ }
2049
+ }, {
2050
+ key: "unAllocatePlayer",
2051
+ value: function unAllocatePlayer(player) {
2052
+ if (player) {
2053
+ var type = this.getMediaTypeFromEl(player.el());
2054
+ this.allocatedPlayers[type] = this.allocatedPlayers[type].filter(function (p) {
2055
+ return p != player;
2056
+ });
2057
+ player.controls(false);
2058
+ player.getMediaElement().loop = false;
2059
+ player.playsinline(false);
2060
+ player.getMediaElement().setAttribute('src', blankSources[type]);
2061
+ player.poster('');
2062
+ clearTextTracks(player);
2063
+ this.unAllocatedPlayers[type].push(player);
2064
+ }
2065
+ }
2066
+ }, {
2067
+ key: "blessAll",
2068
+ value: function blessAll(value) {
2069
+ var _this = this;
2070
+
2071
+ if (this.unAllocatedPlayers[MediaType.AUDIO] == undefined || this.unAllocatedPlayers[MediaType.VIDEO] == undefined) {
2072
+ this.populateMediaPool_();
2073
+ }
2074
+
2075
+ this.forEachMediaType(function (key) {
2076
+ _this.allPlayersForType(MediaType[key]).forEach(function (player) {
2077
+ player.muted(value);
2078
+ });
2079
+ });
2080
+ }
2081
+ }, {
2082
+ key: "allPlayersForType",
2083
+ value: function allPlayersForType(type) {
2084
+ if (this.unAllocatedPlayers[type]) {
2085
+ return [].concat(_toConsumableArray(this.unAllocatedPlayers[type]), _toConsumableArray(this.allocatedPlayers[type]));
2086
+ }
2087
+
2088
+ return [];
2089
+ }
2090
+ }, {
2091
+ key: "getMediaTypeFromEl",
2092
+ value: function getMediaTypeFromEl(mediaElement) {
2093
+ var tagName = mediaElement.tagName.toLowerCase();
2094
+
2095
+ if (tagName == 'div') {
2096
+ tagName = mediaElement.children[0].tagName.toLowerCase();
2097
+ }
2098
+
2099
+ return this.getMediaType(tagName);
2100
+ }
2101
+ }, {
2102
+ key: "getMediaType",
2103
+ value: function getMediaType(tagName) {
2104
+ switch (tagName) {
2105
+ case 'audio':
2106
+ return MediaType.AUDIO;
2107
+
2108
+ case 'video':
2109
+ return MediaType.VIDEO;
2110
+ }
2111
+ }
2112
+ }, {
2113
+ key: "forEachMediaType",
2114
+ value: function forEachMediaType(callbackFn) {
2115
+ Object.keys(MediaType).forEach(callbackFn.bind(this));
2116
+ }
2117
+ }, {
2118
+ key: "createPlayer_",
2119
+ value: function createPlayer_(type, mediaEl) {
2120
+ mediaEl.setAttribute('pool-element', elId++);
2121
+
2122
+ if (!this.unAllocatedPlayers[type]) {
2123
+ this.unAllocatedPlayers[type] = [];
2124
+ this.allocatedPlayers[type] = [];
2125
+ }
2126
+
2127
+ var player = createMediaPlayer({
2128
+ mediaElement: mediaEl,
2129
+ tagName: type
2130
+ });
2131
+ mediaEl.setAttribute('src', blankSources[type]);
2132
+ this.unAllocatedPlayers[type].push(player);
2133
+ return player;
2134
+ }
2135
+ }, {
2136
+ key: "initializeMediaPool_",
2137
+ value: function initializeMediaPool_(type, mediaElSeed) {
2138
+ while (this.allPlayersForType(type).length < this.playerCount) {
2139
+ this.createPlayer_(type, mediaElSeed.cloneNode(true));
2140
+ }
2141
+ }
2142
+ }, {
2143
+ key: "populateMediaPool_",
2144
+ value: function populateMediaPool_() {
2145
+ var _this2 = this;
2146
+
2147
+ this.forEachMediaType(function (key) {
2148
+ var type = MediaType[key];
2149
+
2150
+ var mediaEl = _this2.mediaFactory_[type].call(_this2);
2151
+
2152
+ _this2.initializeMediaPool_(type, mediaEl);
2153
+ });
2154
+ }
2155
+ }]);
2156
+
2157
+ return MediaPool;
2158
+ }();
2159
+
2160
+ function clearTextTracks(player) {
2161
+ var tracks = player.textTracks();
2162
+ var i = tracks.length;
2163
+
2164
+ while (i--) {
2165
+ player.removeRemoteTextTrack(tracks[i]);
2166
+ }
2167
+ }
2168
+
2169
+ var media = {
2170
+ playerPool: new MediaPool(),
2171
+ muteState: true,
2172
+
2173
+ get muted() {
2174
+ return this.muteState;
2175
+ },
2176
+
2177
+ mute: function mute(value) {
2178
+ this.muteState = value;
2179
+ this.playerPool.blessAll(value);
2180
+ this.trigger('change:muted', value);
2181
+ },
2182
+ getPlayer: function getPlayer(fileSource, options) {
2183
+ options.playerType = options.tagName || MediaType.VIDEO;
2184
+ var player = this.playerPool.allocatePlayer(options);
2185
+
2186
+ if (player) {
2187
+ player.muted(this.muteState);
2188
+ player.src(fileSource);
2189
+
2190
+ if (options.textTrackSources) {
2191
+ options.textTrackSources.forEach(function (track) {
2192
+ return player.addRemoteTextTrack(track, true);
2193
+ });
2194
+ }
2195
+
2196
+ return player;
2197
+ }
2198
+ },
2199
+ releasePlayer: function releasePlayer(player) {
2200
+ if (player) {
2201
+ this.playerPool.unAllocatePlayer(player);
2202
+ }
2203
+ }
2204
+ };
2205
+ Object.assign(media, BackboneEvents);
2206
+
2207
+ /**
2208
+ * Play and fade between multiple audio files.
2209
+ *
2210
+ * @class
2211
+ */
2212
+
2213
+ var MultiPlayer = function MultiPlayer(pool, options) {
2214
+ if (options.crossFade && options.playFromBeginning) {
2215
+ throw 'pageflow.Audio.MultiPlayer: The options crossFade and playFromBeginning can not be used together at the moment.';
2216
+ }
2217
+
2218
+ var current = new AudioPlayer.Null();
2219
+ var currentId = null;
2220
+ var that = this;
2221
+ /**
2222
+ * Continue playback.
2223
+ */
2224
+
2225
+ this.resume = function () {
2226
+ return current.play();
2227
+ };
2228
+ /**
2229
+ * Continue playback with fade in.
2230
+ */
2231
+
2232
+
2233
+ this.resumeAndFadeIn = function () {
2234
+ return current.playAndFadeIn(options.fadeDuration);
2235
+ };
2236
+
2237
+ this.seek = function (position) {
2238
+ return current.seek(position);
2239
+ };
2240
+
2241
+ this.pause = function () {
2242
+ return current.pause();
2243
+ };
2244
+
2245
+ this.paused = function () {
2246
+ return current.paused();
2247
+ };
2248
+
2249
+ this.fadeOutAndPause = function () {
2250
+ return current.fadeOutAndPause(options.fadeDuration);
2251
+ };
2252
+
2253
+ this.fadeOutIfPlaying = function () {
2254
+ if (current.paused()) {
2255
+ return Promise.resolve();
2256
+ } else {
2257
+ return current.fadeOutAndPause(options.fadeDuration);
2258
+ }
2259
+ };
2260
+
2261
+ this.position = function () {
2262
+ return current.position;
2263
+ };
2264
+
2265
+ this.duration = function () {
2266
+ return current.duration;
2267
+ };
2268
+
2269
+ this.fadeTo = function (id) {
2270
+ return changeCurrent(id, function (player) {
2271
+ return player.playAndFadeIn(options.fadeDuration);
2272
+ });
2273
+ };
2274
+
2275
+ this.play = function (id) {
2276
+ return changeCurrent(id, function (player) {
2277
+ return player.play();
2278
+ });
2279
+ };
2280
+
2281
+ this.changeVolumeFactor = function (factor) {
2282
+ return current.changeVolumeFactor(factor, options.fadeDuration);
2283
+ };
2284
+
2285
+ this.formatTime = function (time) {
2286
+ return current.formatTime(time);
2287
+ };
2288
+
2289
+ function changeCurrent(id, callback) {
2290
+ if (!options.playFromBeginning && id === currentId && !current.paused()) {
2291
+ return Promise.resolve();
2292
+ }
2293
+
2294
+ var player = pool.get(id);
2295
+ currentId = id;
2296
+ var fadeOutPromise = current.fadeOutAndPause(options.fadeDuration);
2297
+
2298
+ if (current._stopMultiPlayerEventPropagation && current.paused()) {
2299
+ current._stopMultiPlayerEventPropagation();
2300
+ }
2301
+
2302
+ return handleCrossFade(fadeOutPromise).then(function () {
2303
+ current = player;
2304
+ startEventPropagation(current, id);
2305
+ return handlePlayFromBeginning(player).then(function () {
2306
+ return callback(player);
2307
+ });
2308
+ });
2309
+ }
2310
+
2311
+ function handleCrossFade(fadePomise) {
2312
+ if (options.crossFade) {
2313
+ return Promise.resolve();
2314
+ } else {
2315
+ return fadePomise;
2316
+ }
2317
+ }
2318
+
2319
+ function handlePlayFromBeginning(player) {
2320
+ if (options.playFromBeginning || options.rewindOnChange) {
2321
+ return player.rewind();
2322
+ } else {
2323
+ return Promise.resolve();
2324
+ }
2325
+ }
2326
+
2327
+ function startEventPropagation(player, id) {
2328
+ var playCallback = function playCallback() {
2329
+ that.trigger('play', {
2330
+ audioFileId: id
2331
+ });
2332
+ };
2333
+
2334
+ var pauseCallback = function pauseCallback() {
2335
+ that.trigger('pause', {
2336
+ audioFileId: id
2337
+ });
2338
+
2339
+ if (currentId !== id) {
2340
+ player._stopMultiPlayerEventPropagation();
2341
+ }
2342
+ };
2343
+
2344
+ var timeUpdateCallback = function timeUpdateCallback() {
2345
+ that.trigger('timeupdate', {
2346
+ audioFileId: id
2347
+ });
2348
+ };
2349
+
2350
+ var endedCallback = function endedCallback() {
2351
+ that.trigger('ended', {
2352
+ audioFileId: id
2353
+ });
2354
+ };
2355
+
2356
+ var playFailedCallback = function playFailedCallback() {
2357
+ that.trigger('playfailed', {
2358
+ audioFileId: id
2359
+ });
2360
+ };
2361
+
2362
+ player.on('play', playCallback);
2363
+ player.on('pause', pauseCallback);
2364
+ player.on('timeupdate', timeUpdateCallback);
2365
+ player.on('ended', endedCallback);
2366
+ player.on('playfailed', playFailedCallback);
2367
+
2368
+ player._stopMultiPlayerEventPropagation = function () {
2369
+ player.off('play', playCallback);
2370
+ player.off('pause', pauseCallback);
2371
+ player.off('timeupdate', timeUpdateCallback);
2372
+ player.off('ended', endedCallback);
2373
+ player.off('playfailed', playFailedCallback);
2374
+ };
2375
+ }
2376
+ };
2377
+ Object.assign(MultiPlayer.prototype, BackboneEvents);
2378
+
2379
+ var PlayerSourceIDMap = function PlayerSourceIDMap(media) {
2380
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
2381
+ playerOptions = _ref.playerOptions;
2382
+
2383
+ return {
2384
+ current: undefined,
2385
+ previous: undefined,
2386
+ mapSources: function mapSources(id, sources) {
2387
+ this[id] = sources;
2388
+ },
2389
+ get: function get(sourceID) {
2390
+ if (this.previous && this.previous.playerId === sourceID) {
2391
+ var holder = this.current;
2392
+ this.current = this.previous;
2393
+ this.previous = holder;
2394
+ } else {
2395
+ if (this.previous) {
2396
+ media.releasePlayer(this.previous);
2397
+ }
2398
+
2399
+ this.previous = this.current;
2400
+ this.current = media.getPlayer(this[sourceID], _objectSpread2({
2401
+ filePermaId: sourceID,
2402
+ playerId: sourceID
2403
+ }, playerOptions));
2404
+ }
2405
+
2406
+ return this.current;
2407
+ }
2408
+ };
2409
+ };
2410
+
2411
+ var PlayerPool = function PlayerPool(audio, options) {
2412
+ this.players = {};
2413
+
2414
+ this.get = function (audioFileId) {
2415
+ this.players[audioFileId] = this.players[audioFileId] || audio.createPlayer(audioFileId, options);
2416
+ return this.players[audioFileId];
2417
+ };
2418
+
2419
+ this.dispose = function () {
2420
+ this.players = {};
2421
+ };
2422
+ };
2423
+
2424
+ /**
2425
+ * Playing audio files.
2426
+ * @alias pageflow.audio
2427
+ * @member
2428
+ */
2429
+
2430
+ var Audio = function Audio(options) {
2431
+ this.getSources = options.getSources || function (audioFileId) {
2432
+ return options.audioFiles[audioFileId] || '';
2433
+ };
2434
+ /**
2435
+ * Creates a player for the given audio file.
2436
+ *
2437
+ * @param {string|number} audioFileId
2438
+ * Id of the audio file to play. The id can be of the form
2439
+ * `"5.suffix"` to distinguish multiple occurences of the same
2440
+ * audio file for example inside a pageflow.Audio.PlayerPool;
2441
+ *
2442
+ * @param {Object} [options]
2443
+ * Options to pass on player creation
2444
+ *
2445
+ * @static
2446
+ */
2447
+
2448
+
2449
+ this.createPlayer = function (audioFileId, options) {
2450
+ var sources = this.getSources(removeSuffix(audioFileId));
2451
+
2452
+ if (sources) {
2453
+ return new AudioPlayer(sources, _objectSpread2({
2454
+ volumeFading: true
2455
+ }, options));
2456
+ } else {
2457
+ return new AudioPlayer.Null();
2458
+ }
2459
+ };
2460
+ /**
2461
+ * Create a `MultiPlayer` to play and fade between multiple audio
2462
+ * files.
2463
+ *
2464
+ * @param {Object} [options]
2465
+ * All options supported by pageflow.AudioPlayer can be passed.
2466
+ *
2467
+ * @param {number} [options.fadeDuration]
2468
+ * Time in milliseconds to fade audios in and out.
2469
+ *
2470
+ * @param {boolean} [options.playFromBeginning=false]
2471
+ * Always restart audio files from the beginning.
2472
+ *
2473
+ * @param {boolean} [options.rewindOnChange=false]
2474
+ * Play from beginning when changing audio files.
2475
+ *
2476
+ * @return {pageflow.Audio.MultiPlayer}
2477
+ */
2478
+
2479
+
2480
+ this.createMultiPlayer = function (options) {
2481
+ return new MultiPlayer(new PlayerPool(this, options), options);
2482
+ };
2483
+
2484
+ function removeSuffix(id) {
2485
+ if (!id) {
2486
+ return id;
2487
+ }
2488
+
2489
+ return parseInt(id.toString().split('.')[0], 10);
2490
+ }
2491
+ };
2492
+
2493
+ Audio.setup = function (options) {
2494
+ state.audio = new Audio(options);
2495
+ };
2496
+
2497
+ Audio.PlayerPool = PlayerPool;
2498
+
2499
+ var isEventAdded = false;
2500
+ var callbacks = [];
2501
+
2502
+ var muteInBackground = function muteInBackground() {
2503
+ callbacks.forEach(function (cb) {
2504
+ cb(document.visibilityState);
2505
+ });
2506
+ };
2507
+
2508
+ function documentHiddenState(callback) {
2509
+ callbacks.push(callback);
2510
+
2511
+ if (!isEventAdded) {
2512
+ isEventAdded = true;
2513
+ document.addEventListener('visibilitychange', muteInBackground, false);
2514
+ }
2515
+
2516
+ return {
2517
+ removeCallback: function removeCallback() {
2518
+ callbacks = callbacks.filter(function (c) {
2519
+ return c !== callback;
2520
+ });
2521
+ }
2522
+ };
2523
+ }
2524
+
2525
+ export { Audio, AudioPlayer, BLANK_AUDIO_SRC, BLANK_VIDEO_SRC, Features, MediaPool, MediaType, MultiPlayer, PlayerSourceIDMap, VideoPlayer, assetUrls, audioContext, blankSources, browser, cookies, debugMode, documentHiddenState, events, features, log, media, mediaPlayer, settings };