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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +338 -85
- data/admins/pageflow/accounts.rb +1 -98
- data/admins/pageflow/entry.rb +21 -1
- data/admins/pageflow/entry_templates.rb +140 -0
- data/admins/pageflow/membership.rb +12 -0
- data/admins/pageflow/user.rb +5 -3
- data/app/assets/javascripts/pageflow/admin/entries.js +65 -0
- data/app/assets/javascripts/pageflow/admin/users.js +1 -1
- data/app/assets/javascripts/pageflow/asset_urls.js.erb +1 -0
- data/app/assets/javascripts/pageflow/base.js +0 -12
- data/app/assets/javascripts/pageflow/components.js +2 -6
- data/app/assets/javascripts/pageflow/dist/ui.js +47 -14
- data/app/assets/javascripts/pageflow/vendor.js +13 -10
- data/app/assets/stylesheets/pageflow/base.scss +0 -7
- data/app/assets/stylesheets/pageflow/editor/base.scss +2 -0
- data/app/assets/stylesheets/pageflow/editor/composables.scss +5 -1
- data/app/assets/stylesheets/pageflow/editor/emulation_mode_button.scss +44 -55
- data/app/assets/stylesheets/pageflow/editor/help.scss +2 -2
- data/app/assets/stylesheets/pageflow/ui/tooltip.scss +17 -3
- data/app/helpers/pageflow/admin/entries_helper.rb +16 -0
- data/app/helpers/pageflow/structured_data_helper.rb +0 -2
- data/app/models/pageflow/account.rb +21 -1
- data/app/models/pageflow/entry.rb +9 -2
- data/app/models/pageflow/entry_duplicate.rb +1 -0
- data/app/models/pageflow/entry_template.rb +16 -2
- data/app/policies/pageflow/account_policy.rb +10 -0
- data/app/policies/pageflow/entry_template_policy.rb +5 -1
- data/app/views/admin/accounts/_entry_template_details.html.arb +7 -5
- data/app/views/admin/accounts/_form.html.erb +3 -49
- data/app/views/admin/entries/_attributes_table.html.arb +5 -0
- data/app/views/admin/entries/_not_allowed_to_see_entry_types.json.jbuilder +2 -0
- data/app/views/admin/entries/entry_types.json.jbuilder +4 -0
- data/app/views/admin/entry_templates/_form.html.erb +58 -0
- data/app/views/admin/users/_not_allowed_to_see_user_quota.html.erb +3 -0
- data/app/views/components/pageflow/admin/entry_templates_tab.rb +48 -0
- data/app/views/pageflow/admin/users/_quota_exhausted.html.erb +1 -1
- data/config/initializers/admin_resource_tabs.rb +5 -0
- data/config/initializers/help_entries.rb +1 -5
- data/config/locales/de.yml +88 -155
- data/config/locales/en.yml +79 -143
- data/db/migrate/20200515112500_add_constraints_to_entry_templates.rb +21 -0
- data/db/migrate/20200807135200_rename_pageflow_entry_template_entry_type_to_entry_type_name.rb +7 -0
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/components.js +7 -0
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/editor.js +1479 -1391
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/dist/frontend.js +9218 -0
- data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-client.js +1 -1
- data/{app/assets/javascripts/pageflow → entry_types/paged/app/assets/javascripts/pageflow_paged}/dist/react-server.js +3 -3
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/frontend.js +6 -0
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/server_rendering.js +9 -0
- data/entry_types/paged/app/assets/javascripts/pageflow_paged/vendor.js +8 -0
- data/entry_types/paged/app/controllers/pageflow_paged/application_controller.rb +2 -2
- data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/page_background_asset_helper.rb +4 -3
- data/{app/helpers/pageflow → entry_types/paged/app/helpers/pageflow_paged}/react_server_side_rendering_helper.rb +23 -2
- data/entry_types/paged/app/views/layouts/pageflow_paged/application.html.erb +2 -2
- data/entry_types/paged/app/views/pageflow_paged/editor/entries/_head.html.erb +2 -2
- data/entry_types/paged/app/views/pageflow_paged/entries/_entry.html.erb +1 -1
- data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/page_background_asset/_element.html.erb +0 -0
- data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/_widget.html.erb +0 -0
- data/{app/views/pageflow → entry_types/paged/app/views/pageflow_paged}/react/page.html.erb +0 -0
- data/entry_types/paged/config/initializers/features.rb +1 -1
- data/entry_types/paged/config/initializers/help_entries.rb +17 -0
- data/entry_types/paged/config/locales/new/help.de.yml +162 -0
- data/entry_types/paged/config/locales/new/help.en.yml +153 -0
- data/entry_types/paged/lib/pageflow_paged/engine.rb +13 -0
- data/entry_types/paged/lib/pageflow_paged/plugin.rb +5 -1
- data/entry_types/paged/lib/pageflow_paged/react.rb +12 -0
- data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/page_type.rb +2 -2
- data/{lib/pageflow → entry_types/paged/lib/pageflow_paged}/react/widget_type.rb +2 -2
- data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react-server.js +20613 -0
- data/entry_types/paged/vendor/assets/javascripts/development/pageflow_paged/vendor/react.js +21495 -0
- data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react-server.js +24 -0
- data/entry_types/paged/vendor/assets/javascripts/production/pageflow_paged/vendor/react.js +24 -0
- data/entry_types/scrolled/app/assets/javascripts/pageflow_scrolled/legacy.js +0 -0
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/chapters_controller.rb +2 -2
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/content_elements_controller.rb +14 -4
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/editor/sections_controller.rb +2 -2
- data/entry_types/scrolled/app/controllers/pageflow_scrolled/entries_controller.rb +8 -0
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/editor/seed_html_helper.rb +6 -0
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/entry_json_seed_helper.rb +2 -0
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/react_server_side_rendering_helper.rb +33 -0
- data/entry_types/scrolled/app/helpers/pageflow_scrolled/themes_helper.rb +8 -0
- data/entry_types/scrolled/app/models/pageflow_scrolled/content_element.rb +38 -0
- data/entry_types/scrolled/app/views/pageflow_scrolled/editor/content_elements/batch.json.jbuilder +2 -0
- data/entry_types/scrolled/app/views/pageflow_scrolled/editor/entries/_head.html.erb +1 -7
- data/entry_types/scrolled/app/views/pageflow_scrolled/entries/show.html.erb +19 -3
- data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_entry.json.jbuilder +3 -0
- data/entry_types/scrolled/app/views/pageflow_scrolled/entry_json_seed/_theme.json.jbuilder +7 -0
- data/entry_types/scrolled/config/initializers/help_entries.rb +16 -0
- data/entry_types/scrolled/config/locales/new/de.yml +345 -13
- data/entry_types/scrolled/config/locales/new/en.yml +257 -14
- data/entry_types/scrolled/config/routes.rb +1 -0
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/install_generator.rb +28 -0
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoDesktop.svg +56 -0
- data/entry_types/scrolled/lib/generators/pageflow_scrolled/install/templates/theme/logoMobile.svg +22 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/engine.rb +4 -0
- data/entry_types/scrolled/lib/pageflow_scrolled/plugin.rb +3 -1
- data/entry_types/scrolled/lib/pageflow_scrolled/seeds.rb +90 -30
- data/entry_types/scrolled/lib/tasks/pageflow_scrolled_tasks.rake +64 -27
- data/entry_types/scrolled/package/contentElements-editor.js +242 -183
- data/entry_types/scrolled/package/contentElements-frontend.css +1 -0
- data/entry_types/scrolled/package/contentElements-frontend.js +624 -279
- data/entry_types/scrolled/package/editor.js +2561 -363
- data/entry_types/scrolled/package/frontend-server.js +228 -0
- data/entry_types/scrolled/package/frontend/EditableText-4264c349.js +1993 -0
- data/entry_types/scrolled/package/frontend/Wavesurfer-c3c45324.js +378 -0
- data/entry_types/scrolled/package/frontend/components-cfe6a479.js +2115 -0
- data/entry_types/scrolled/package/frontend/getPrototypeOf-63c7c8e8.js +86 -0
- data/entry_types/scrolled/package/frontend/index.css +9 -0
- data/entry_types/scrolled/package/frontend/index.js +4425 -0
- data/entry_types/scrolled/package/package.json +17 -6
- data/entry_types/scrolled/spec/fixtures/audio.m4a +0 -0
- data/entry_types/scrolled/spec/fixtures/video.mp4 +0 -0
- data/lib/generators/pageflow/initializer/templates/pageflow.rb +20 -9
- data/lib/pageflow/ability_mixin.rb +14 -2
- data/lib/pageflow/configuration.rb +6 -5
- data/lib/pageflow/engine.rb +1 -0
- data/lib/pageflow/entry_type_configuration.rb +1 -0
- data/lib/pageflow/global_config_api.rb +5 -4
- data/lib/pageflow/react.rb +4 -2
- data/lib/pageflow/version.rb +1 -1
- data/{packages/pageflow → package}/config/jest/index.js +2 -1
- data/{packages/pageflow → package}/config/jest/transformers/jst.js +0 -0
- data/{packages/pageflow → package}/config/jest/transformers/upwardBabel.js +0 -0
- data/package/config/webpack.js +22 -0
- data/{packages/pageflow → package}/editor.js +480 -1129
- data/package/frontend.js +2525 -0
- data/{packages/pageflow → package}/package.json +3 -0
- data/{packages/pageflow → package}/testHelpers.js +114 -13
- data/{packages/pageflow → package}/ui.js +47 -14
- data/spec/factories/accounts.rb +3 -1
- data/spec/factories/entry_templates.rb +1 -0
- data/spec/factories/published_entries.rb +6 -1
- metadata +62 -26
- data/app/assets/javascripts/pageflow/dist/frontend.js +0 -5800
- data/config/initializers/entry_types.rb +0 -4
- data/entry_types/scrolled/package/frontend.js +0 -2879
- data/packages/pageflow/config/jest/transformers/cssModules.js +0 -1
- data/packages/pageflow/config/webpack.js +0 -14
data/package/frontend.js
ADDED
@@ -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 };
|