diff --git a/.gitattributes b/.gitattributes index fdc43f48..a8d77a28 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,24 @@ +# +# Exclude these files from release archives. +# This will also make them unavailable when using Composer with `--prefer-dist`. +# If you develop for Clicky using Composer, use `--prefer-source`. +# https://www.reddit.com/r/PHP/comments/2jzp6k/i_dont_need_your_tests_in_my_production +# https://blog.madewithlove.be/post/gitattributes/ +# +/.gitattributes export-ignore +/.gitignore export-ignore +package.json export-ignore +package-lock.json export-ignore +contributing.md export-ignore +code-of-conduct.md export-ignore +_config.yml +Gruntfile.js +/stylesheets export-ignore +/scripts export-ignore +/demos export-ignore +/media export-ignore +/images export-ignore + # Set the default behavior, in case people don't have core.autocrlf set. # Git will always convert line endings to LF on checkout, even on Windows * text eol=lf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..71299c96 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,42 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Version tested** +Which version of AblePlayer are you reporting against? + - Main (the current release) + - Develop (the next release) + - A specific branch other than main or develop. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/docs_existing.md b/.github/ISSUE_TEMPLATE/docs_existing.md new file mode 100644 index 00000000..f8f9f08b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs_existing.md @@ -0,0 +1,26 @@ +--- +name: Documentation (Existing) +about: Edits to existing documentation needed +title: '' +labels: '' +assignees: '' + +--- + +**URL** +page URL + +**Title** +Title of the existing documentation + +**What Needs Editing?** +Describe the steps using: +1. +2. +3. + +**Screenshots** +If applicable, add screenshots for the above steps + +**Additional context** +Add any other context. diff --git a/.github/ISSUE_TEMPLATE/docs_new.md b/.github/ISSUE_TEMPLATE/docs_new.md new file mode 100644 index 00000000..e0b5fce6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs_new.md @@ -0,0 +1,26 @@ +--- +name: Documentation (New) +about: New documentation needed +title: '' +labels: '' +assignees: '' + +--- + +**Title** +Suggested title of the new documentation + +**Description** +Describe what the new page is about + +**Instruction Steps** +Describe the steps using: +1. +2. +3. + +**Screenshots** +If applicable, add screenshots for the above steps + +**Additional context** +Add any other context. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..bbcbbe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..628cfc07 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ + + +## Description + + + +## How Has This Been Tested? + + + + +## Screenshots (jpeg or gifs if applicable): + +## Types of changes + + + + + +## Checklist: +- [ ] My code is tested. +- [ ] My code has proper inline documentation. diff --git a/.gitignore b/.gitignore index ee16fc95..4122dad7 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ npm-debug.log translations/???.js .idea .htaccess +docs +jsdoc.json \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 7b6eda3e..afb191cd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,108 +1,185 @@ -module.exports = function(grunt) { +module.exports = function (grunt) { + grunt.loadNpmTasks("grunt-contrib-concat"); + grunt.loadNpmTasks("grunt-contrib-copy"); + grunt.loadNpmTasks("grunt-contrib-cssmin"); + grunt.loadNpmTasks("grunt-contrib-clean"); + grunt.loadNpmTasks("grunt-remove-logging"); + grunt.loadNpmTasks("grunt-decomment"); + grunt.loadNpmTasks("grunt-contrib-jshint"); + grunt.loadNpmTasks("grunt-terser"); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-cssmin'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks("grunt-remove-logging"); - grunt.loadNpmTasks('grunt-contrib-jshint'); - - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - concat: { - build: { - src: [ - // Ultimately this should be just 'scripts/*.js', - // but for now we're maintaining the order which was - // specified in the previous 'compile.sh' script - 'scripts/ableplayer-base.js', - 'scripts/initialize.js', - 'scripts/preference.js', - 'scripts/webvtt.js', - 'scripts/buildplayer.js', - 'scripts/track.js', - 'scripts/youtube.js', - 'scripts/slider.js', - 'scripts/volume.js', - 'scripts/dialog.js', - 'scripts/misc.js', - 'scripts/description.js', - 'scripts/browser.js', - 'scripts/control.js', - 'scripts/caption.js', - 'scripts/chapters.js', - 'scripts/metadata.js', - 'scripts/transcript.js', - 'scripts/search.js', - 'scripts/event.js', - 'scripts/dragdrop.js', - 'scripts/sign.js', - 'scripts/langs.js', - 'scripts/translation.js', - 'scripts/ttml2webvtt.js', - 'scripts/JQuery.doWhen.js', - 'scripts/vts.js', - 'scripts/vimeo.js' - ], - dest: 'build/<%= pkg.name %>.js' - }, + grunt.initConfig({ + pkg: grunt.file.readJSON("package.json"), + concat: { + options: { + banner: "/*! <%= pkg.name %> V<%= pkg.version %> with DOMPurify included */\n", + process: function(src, filepath) { + // Remove the source map reference line only from the dompurify file + if (filepath.includes('dompurify')) { + return src.replace(/\/\/# sourceMappingURL=.*\.map/g, ''); + } + return src; + } + }, + build: { + src: [ + "node_modules/dompurify/dist/purify.js", + "scripts/ableplayer-base.js", + "scripts/initialize.js", + "scripts/preference.js", + "scripts/webvtt.js", + "scripts/buildplayer.js", + "scripts/validate.js", + "scripts/track.js", + "scripts/youtube.js", + "scripts/slider.js", + "scripts/volume.js", + "scripts/dialog.js", + "scripts/misc.js", + "scripts/description.js", + "scripts/browser.js", + "scripts/control.js", + "scripts/caption.js", + "scripts/chapters.js", + "scripts/metadata.js", + "scripts/transcript.js", + "scripts/search.js", + "scripts/event.js", + "scripts/dragdrop.js", + "scripts/sign.js", + "scripts/langs.js", + "scripts/translation.js", + "scripts/vts.js", + "scripts/vimeo.js", + ], + dest: "build/<%= pkg.name %>.js", + }, + build_separate_dompurify: { + options: { + banner: "/*! <%= pkg.name %> V<%= pkg.version %> - In this file, DOMPurify is not bundled in with AblePlayer, but is a required dependency that can be added to the project via a local copy or a CDN */\n", }, - removelogging: { - dist: { - src: [ - 'build/<%= pkg.name %>.js' - ], - dest: 'build/<%= pkg.name %>.dist.js' - }, - options: { - // Remove all console output (see https://www.npmjs.com/package/grunt-remove-logging) - } + src: [ + "scripts/ableplayer-base.js", + "scripts/initialize.js", + "scripts/preference.js", + "scripts/webvtt.js", + "scripts/buildplayer.js", + "scripts/validate.js", + "scripts/track.js", + "scripts/youtube.js", + "scripts/slider.js", + "scripts/volume.js", + "scripts/dialog.js", + "scripts/misc.js", + "scripts/description.js", + "scripts/browser.js", + "scripts/control.js", + "scripts/caption.js", + "scripts/chapters.js", + "scripts/metadata.js", + "scripts/transcript.js", + "scripts/search.js", + "scripts/event.js", + "scripts/dragdrop.js", + "scripts/sign.js", + "scripts/langs.js", + "scripts/translation.js", + "scripts/vts.js", + "scripts/vimeo.js", + ], + dest: "build/separate-dompurify/<%= pkg.name %>.js", + }, + }, + removelogging: { + dist: { + src: ["build/<%= pkg.name %>.js"], + dest: "build/<%= pkg.name %>.dist.js", + }, + dist_separate_dompurify: { + src: ["build/separate-dompurify/<%= pkg.name %>.js"], + dest: "build/separate-dompurify/<%= pkg.name %>.dist.js", + }, + options: { + // Remove all console output (see https://www.npmjs.com/package/grunt-remove-logging) + }, + }, + decomment: { + any: { + options: { + safe: true, + }, + files: { + "build/<%= pkg.name %>.dist.js": "build/<%= pkg.name %>.dist.js", + }, + + } + }, + terser: { + min: { + files: { + "build/<%= pkg.name %>.min.js": ["build/<%= pkg.name %>.dist.js"], }, - uglify: { - min: { - src : ['build/<%= pkg.name %>.dist.js'], - dest : 'build/<%= pkg.name %>.min.js', - }, - options: { - // Add a banner with the package name and version - // (no date, otherwise a new build is different even if the code didn't change!) - banner: '/*! <%= pkg.name %> V<%= pkg.version %> */\n', - // Preserve comments that start with a bang (like the file header) - preserveComments: "some" - } + options: { + ecma: 2015, // Specify ECMAScript version to support ES6+ + keep_fnames: true, + output: { + comments: /^!/, + }, }, - cssmin: { - min: { - src : [ - 'styles/ableplayer.css', - ], - dest : 'build/<%= pkg.name %>.min.css', - }, - options: { - // Add a banner with the package name and version - // (no date, otherwise a new build is different even if the code didn't change!) - // (oddly, here we don't need a '\n' at the end!) - banner: '/*! <%= pkg.name %> V<%= pkg.version %> */', - } + }, + min_separate_dompurify: { + files: { + "build/separate-dompurify/<%= pkg.name %>.min.js": ["build/separate-dompurify/<%= pkg.name %>.dist.js"], + "build/separate-dompurify/purify.min.js": ["node_modules/dompurify/dist/purify.js"], }, - jshint: { - files: ['Gruntfile.js', 'scripts/**/*.js'], - options: { - // options here to override JSHint defaults - globals: { - browser: true, - jquery: true, - devel: true, - } - } + options: { + ecma: 2015, // Specify ECMAScript version to support ES6+ + keep_fnames: true, + output: { + comments: /^!/, + }, }, - clean: { - build: ['build'], + }, + }, + cssmin: { + min: { + src: ["styles/ableplayer.css"], + dest: "build/<%= pkg.name %>.min.css", + }, + options: { + // Add a banner with the package name and version + // (no date, otherwise a new build is different even if the code didn't change!) + // (oddly, here we don't need a '\n' at the end!) + banner: "/*! <%= pkg.name %> V<%= pkg.version %> */", + }, + }, + jshint: { + files: ["Gruntfile.js", "scripts/**/*.js"], + options: { + // options here to override JSHint defaults + globals: { + browser: true, + jquery: true, + devel: true, }, + }, + }, + clean: { + build: ["build"], + }, + }); - }); - - grunt.registerTask('default', ['concat', 'removelogging', 'uglify', 'cssmin']); - grunt.registerTask('test', ['jshint']); -}; + grunt.registerTask("default", [ + "concat:build", + "removelogging:dist", + "decomment", + "terser:min", + "cssmin", + ]); + grunt.registerTask("build_separate_dompurify", [ + "concat:build_separate_dompurify", + "removelogging:dist_separate_dompurify", + "terser:min_separate_dompurify", + ]); + grunt.registerTask("test", ["jshint"]); +}; \ No newline at end of file diff --git a/LICENSE b/LICENSE index 4a1068b1..916a0a8b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,10 +1,10 @@ The MIT License (MIT) -Copyright (c) 2014 University of Washington +Copyright (c) 2014-2025 The Able Player Contributors -Able Player development is supported in part by The AccessComputing project, -with financial support from the National Science Foundation -(grant #CNS-0540615, CNS-0837508, and CNS-1042260); +Able Player development was supported in part by The AccessComputing project until 2025, +with financial support from the National Science Foundation +(grant #CNS-0540615, CNS-0837508, and CNS-1042260); and by the Committee on Institutional Cooperation (CIC). Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index 9cc65163..ccebdf1d 100644 --- a/README.md +++ b/README.md @@ -1,145 +1,153 @@ -Able Player -========== - -*Able Player* is a fully accessible cross-browser HTML5 media player. - -To see the player in action check out the [Able Player Examples][examples] page. - -Features --------- - -- Supports both audio and video. -- Supports either a single audio track or an entire playlist. -- Includes a full set of player controls that are keyboard-accessible, properly labeled for screen reader users, and controllable by speech recognition users. -- Includes customizable keyboard shortcuts that enable the player to be operated from anywhere on the web page (unless there are multiple instances of the player on a given page; then the player must have focus for keyboard shortcuts to work). -- Features high contrast, scalable controls that remain visible in Windows High Contrast mode, plus an easy-to-see focus indicator so keyboard users can easily tell which control currently has focus. -- Supports closed captions and subtitles in Web Video Timed Text (WebVTT) format, the standard format recommended by the HTML5 specification. -- Supports chapters, also using WebVTT. Chapters are specific landing points in the video, allowing video content to have structure and be more easily navigated. -- Supports text-based audio description, also using WebVTT. At designated times, the description text is read aloud by browsers, or by screen readers for browsers that don't support the Web Speech API. Users can optionally set their player to pause when audio description starts in order to avoid conflicts between the description and program audio. -- Supports audio description as a separate video. When two videos are available (one with description and one without), both can be delivered together using the same player and users can toggle between the versions. -- Supports adjustable playback rate. Users who need to slow down the video in order to better process and understand its content can do so; and users who need to speed up the video in order to maintain better focus can do so. -- Includes an interactive transcript feature, built from the WebVTT chapter, caption and description files as the page is loaded. Users can click anywhere in the transcript to start playing the video (or audio) at that point. Keyboard users can also choose to keyboard-enable the transcript, so they can tab through its content one caption at a time and press enter to play the media at the desired point. -- Features automatic text highlighting within the transcript as the media plays. This feature is enabled by default but can be turned off if users find it distracting. -- Supports YouTube and Vimeo videos. -- Provides users with the ability to customize the display of captions and subtitles. Users can control the font style, size, and color of caption text; plus background color and transparency; all from the Preferences dialog. They can also choose to position captions *below* the video instead of the default position (an semi-transparent overlay). -- Supports fallback content if the media cannot be played (see section on **Fallback** for details). -- Includes extensive customization options. Many of the features described above are controlled by user preferences. This is based on the belief that every user has different needs and there are no one-size-fits-all solutions. This is the heart of universal design. - -Supported Languages -------------------- - -Able Player has been translated into the following languages. To add another language, see instructions below under **Contributing**. +# Able Player + +![AblePlayer in action, showing the video player with captions, synchronized sign language, and a navigable transcript](https://user-images.githubusercontent.com/55474996/227562765-7a17103c-4c93-4a17-82b4-fc1e401972b0.png) + +*Able Player* is a fully accessible cross-browser HTML5 media player. + +- [Feature List](#feature-list) +- [Supported Languages](#supported-languages) +- [Compatibility](#compatibility) +- [Dependencies](#dependencies) +- [Fallback](#fallback) +- [Setup](#setup) +- [Feature Attributes](#features-attributes) +- [Mime Types](#mime-types) +- [Keyboard Shortcuts](#keyboard-shortcuts) +- [User Preferences](#user-preferences) +- [Acknowledgements](#acknowledgements) + +## Feature List + +- Supports both audio and video. +- Supports either a single audio track or an entire playlist. +- Includes a full set of player controls that are keyboard-accessible, properly labeled for screen reader users, and controllable by speech recognition users. +- Includes customizable keyboard shortcuts that enable the player to be operated from anywhere on the web page (unless there are multiple instances of the player on a given page; then the player must have focus for keyboard shortcuts to work). +- Features high contrast, scalable controls that remain visible in Windows High Contrast mode, plus an easy-to-see focus indicator so keyboard users can easily tell which control currently has focus. +- Supports closed captions and subtitles in Web Video Timed Text (WebVTT) format, the standard format recommended by the HTML5 specification. +- Supports chapters, also using WebVTT. Chapters are specific landing points in the video, allowing video content to have structure and be more easily navigated. +- Supports text-based audio description, also using WebVTT. At designated times, the description text is read aloud by browsers, or by screen readers for browsers that don't support the Web Speech API. Users can optionally set their player to pause when audio description starts to avoid conflicts between the description and program audio. +- Supports audio description as a separate video. When two videos are available (one with description and one without), both can be delivered together using the same player and users can toggle between the versions. +- Supports adjustable playback rate. Users who need to slow down the video to better process and understand its content can do so; and users who need to speed up the video to maintain better focus can do so. +- Includes an interactive transcript feature, built from the WebVTT chapter, caption and description files as the page is loaded. Users can click anywhere in the transcript to start playing the video (or audio) at that point. Keyboard users can also choose to keyboard-enable the transcript, so they can tab through its content one caption at a time and press enter to play the media at the desired point. +- Features automatic text highlighting within the transcript as the media plays. This feature is enabled by default but can be turned off if users find it distracting. +- Supports YouTube and Vimeo videos. +- Provides users with the ability to customize the display of captions and subtitles. Users can control the font style, size, and color of caption text; plus background color and transparency; all from the Preferences dialog. They can also choose to position captions *below* the video instead of the default position (an semi-transparent overlay). +- Supports fallback content if the media cannot be played (see section on **Fallback** for details). +- Includes extensive customization options. Many of the features described above are controlled by user preferences. This is based on the belief that every user has different needs and there are no one-size-fits-all solutions. This is the heart of universal design. + +## Supported Languages + +Able Player has been translated into the following languages. -Contributing -------------- +## Compatibility -There are many ways to contribute to Able Player, and we welcome and appreciate your help! Here are some options: +During development, *Able Player* is routinely tested with the latest versions of the following browsers. -- If you spot bugs are have feature requests, please submit them to the [Issues][issues] queue. -- If you have code to contribute, please note that all development occurs on the [develop branch][develop]. This is often many commits ahead of the master branch, so please do all development from *develop*, and submit pull requests there. We particularly appreciate help with any issues in the Issues queue that have been flagged with "help wanted". -- If you are multilingual, please consider translating Able Player into another language! All labels, prompts, messages, and help text for each language are contained within a single file, contained within the */translations* directory. +### Windows +- Chrome +- Firefox +- Edge -Compatibility -------------- +### Mac OS +- Chrome +- Firefox +- Safari +- Opera -*Able Player* has been tested with the following browsers. +### iOS (iPhone and iPad) +- Safari -- Firefox 3.x and higher -- Internet Explorer 10 and higher -- Microsoft Edge all versions -- Google Chrome 7.0 and higher -- Opera 10.63 and higher -- Safari 5.0 on Mac OS X -- Safari on IOS 3.2.2 and higher -- Chrome on Android 4.2 and higher +### Android (Google Pixel) +- Chrome +- Firefox -Note that mobile browsers have limitations (e.g., volume control and autostart are not supported) +Since the release of version 4.4, we are no longer supporting Internet Explorer. -Dependencies ------------- +## Dependencies -*Able Player* has the following third party dependencies: +*Able Player* has the following third party dependencies: -- *Able Player* uses [jQuery][]. Version 3.2.1 or higher is recommended. +- *Able Player* uses [jQuery][]. Version 3.5.0 or higher is recommended. The example code below uses Google’s hosted libraries; no download required. -- *Able Player* uses [js-cookie][] to store and retrieve user - preferences in cookies. This script is distributed with *Able - Player*. Prior to version 2.3, Able Player used [jquery.cookie][] - for this same purpose. - +- *Able Player* optionally can use [js-cookie][] to store and retrieve user + preferences in cookies. By default, preferences are stored in localStorage. + The example code below uses CDN’s hosted libraries; no download required. + All Able Player cookies are functional cookies. +- *AblePlayer*, as of 4.5.1, requires the use of the DOMPurify sanitizing library. + - The default files in the root of the `/build` directory have DOMPurify bundled in. + - Alternatively, the `build/separate-dompurify` directory houses copies of the AblePlayer files with AblePlayer code only and a stand-alone copy of the current version of DOMPurify that the project is currently using. These files are available for those who want to load DOMPurify via a separate file or want to use a CDN hosted version. + To install Able Player, copy the following files from the Able Player repo into a folder on your web server: -- build/* -- button-icons/* -- images/* -- styles/* (optional, see note below) -- thirdparty/* (includes js-cookie, as mentioned above) -- translations/* -- LICENSE - -The *build* folder includes minified production code (*ableplayer.min.js* and *ableplayer.min.css*). -For debugging and/or style customization purposes, human-readable source files are also available: -- build/ableplayer.js -- styles/ableplayer.css - - -Fallback --------- - -All modern browsers have supported HTML5 media elements for many years. -However, there are still older browsers in use that don’t have this support -(e.g., Internet Explorer 9 and earlier). For these, you need to provide fallback content. - -Prior to version 4.0, *Able Player* used [JW Player][] as a fallback Flash player -for older browsers. However, this solution was built specifically on **JW Player 6** -which is now many versions old and difficult to find. - -Also, prior to version 4.0, *Able Player* used [Modernizr][] to enable -styling of HTML5 elements in Internet Explorer 6 through 8. This too is no longer -supported, and Modernizr is no longer needed. - -Instead, we recommend providing alternative content as a child of the `