Merge lp:~openlp-dev/openlp/webengine-migrate into lp:openlp
- webengine-migrate
- Merge into trunk
Proposed by
Tomas Groth
Status: | Superseded |
---|---|
Proposed branch: | lp:~openlp-dev/openlp/webengine-migrate |
Merge into: | lp:openlp |
Diff against target: |
33116 lines (+15169/-5298) 370 files modified
.bzrignore (+7/-0) karma.conf.js (+77/-0) nose2.cfg (+8/-8) openlp/.version (+1/-1) openlp/core/api/deploy.py (+1/-1) openlp/core/api/endpoint/controller.py (+8/-6) openlp/core/api/endpoint/core.py (+2/-2) openlp/core/api/endpoint/remote.py (+1/-0) openlp/core/api/endpoint/service.py (+1/-0) openlp/core/api/http/server.py (+6/-7) openlp/core/api/http/wsgiapp.py (+1/-0) openlp/core/api/tab.py (+4/-3) openlp/core/api/websockets.py (+1/-0) openlp/core/app.py (+10/-7) openlp/core/common/actions.py (+1/-1) openlp/core/common/applocation.py (+2/-1) openlp/core/common/db.py (+1/-0) openlp/core/common/httputils.py (+1/-0) openlp/core/common/i18n.py (+2/-1) openlp/core/common/mixins.py (+1/-0) openlp/core/common/path.py (+1/-0) openlp/core/common/registry.py (+2/-0) openlp/core/common/settings.py (+41/-4) openlp/core/display/html/black.css (+292/-0) openlp/core/display/html/display.html (+39/-0) openlp/core/display/html/display.js (+789/-0) openlp/core/display/html/reveal.css (+1591/-0) openlp/core/display/html/reveal.js (+5586/-0) openlp/core/display/html/textFit.js (+237/-0) openlp/core/display/render.py (+738/-0) openlp/core/display/renderer.py (+0/-586) openlp/core/display/screens.py (+283/-181) openlp/core/display/webengine.py (+93/-0) openlp/core/display/window.py (+404/-0) openlp/core/lib/__init__.py (+97/-307) openlp/core/lib/db.py (+4/-3) openlp/core/lib/htmlbuilder.py (+9/-7) openlp/core/lib/imagemanager.py (+6/-5) openlp/core/lib/mediamanageritem.py (+6/-5) openlp/core/lib/plugin.py (+1/-0) openlp/core/lib/pluginmanager.py (+2/-0) openlp/core/lib/serviceitem.py (+105/-191) openlp/core/lib/settingstab.py (+4/-4) openlp/core/lib/theme.py (+9/-7) openlp/core/lib/ui.py (+1/-0) openlp/core/loader.py (+1/-1) openlp/core/projectors/constants.py (+1/-0) openlp/core/projectors/db.py (+7/-3) openlp/core/projectors/editform.py (+6/-5) openlp/core/projectors/manager.py (+6/-5) openlp/core/projectors/pjlink.py (+6/-5) openlp/core/projectors/sourceselectform.py (+2/-1) openlp/core/projectors/tab.py (+5/-4) openlp/core/projectors/upgrade.py (+2/-1) openlp/core/resources.py (+1/-1) openlp/core/server.py (+1/-1) openlp/core/ui/aboutform.py (+1/-0) openlp/core/ui/advancedtab.py (+5/-4) openlp/core/ui/exceptiondialog.py (+4/-4) openlp/core/ui/exceptionform.py (+7/-46) openlp/core/ui/filerenamedialog.py (+3/-3) openlp/core/ui/filerenameform.py (+1/-1) openlp/core/ui/firsttimeform.py (+42/-39) openlp/core/ui/firsttimelanguagedialog.py (+3/-3) openlp/core/ui/firsttimelanguageform.py (+2/-1) openlp/core/ui/firsttimewizard.py (+29/-32) openlp/core/ui/formattingtagdialog.py (+4/-4) openlp/core/ui/formattingtagform.py (+1/-1) openlp/core/ui/generaltab.py (+8/-144) openlp/core/ui/icons.py (+2/-1) openlp/core/ui/maindisplay.py (+0/-602) openlp/core/ui/mainwindow.py (+20/-27) openlp/core/ui/media/endpoint.py (+1/-0) openlp/core/ui/media/mediacontroller.py (+5/-4) openlp/core/ui/media/playertab.py (+4/-4) openlp/core/ui/media/systemplayer.py (+2/-1) openlp/core/ui/media/vendor/vlc.py (+1197/-892) openlp/core/ui/media/vlcplayer.py (+2/-1) openlp/core/ui/media/webkitplayer.py (+0/-312) openlp/core/ui/plugindialog.py (+3/-3) openlp/core/ui/pluginform.py (+2/-1) openlp/core/ui/printservicedialog.py (+4/-4) openlp/core/ui/printserviceform.py (+3/-2) openlp/core/ui/screenstab.py (+97/-0) openlp/core/ui/serviceitemeditdialog.py (+4/-4) openlp/core/ui/serviceitemeditform.py (+3/-3) openlp/core/ui/servicemanager.py (+20/-16) openlp/core/ui/servicenoteform.py (+4/-4) openlp/core/ui/settingsdialog.py (+3/-3) openlp/core/ui/settingsform.py (+21/-13) openlp/core/ui/shortcutlistdialog.py (+3/-3) openlp/core/ui/shortcutlistform.py (+2/-1) openlp/core/ui/slidecontroller.py (+165/-167) openlp/core/ui/splashscreen.py (+2/-2) openlp/core/ui/starttimedialog.py (+3/-3) openlp/core/ui/starttimeform.py (+1/-1) openlp/core/ui/style.py (+1/-0) openlp/core/ui/themeform.py (+14/-8) openlp/core/ui/themelayoutdialog.py (+3/-3) openlp/core/ui/themelayoutform.py (+1/-1) openlp/core/ui/thememanager.py (+10/-10) openlp/core/ui/themestab.py (+7/-7) openlp/core/ui/themewizard.py (+4/-4) openlp/core/version.py (+54/-2) openlp/core/widgets/docks.py (+2/-1) openlp/core/widgets/edits.py (+2/-1) openlp/core/widgets/layouts.py (+185/-0) openlp/core/widgets/toolbar.py (+1/-0) openlp/core/widgets/views.py (+40/-38) openlp/core/widgets/widgets.py (+267/-1) openlp/core/widgets/wizard.py (+5/-4) openlp/plugins/alerts/alertsplugin.py (+3/-2) openlp/plugins/alerts/endpoint.py (+1/-0) openlp/plugins/alerts/forms/__init__.py (+1/-1) openlp/plugins/alerts/forms/alertdialog.py (+4/-4) openlp/plugins/alerts/forms/alertform.py (+2/-1) openlp/plugins/alerts/lib/alertsmanager.py (+5/-4) openlp/plugins/alerts/lib/alertstab.py (+3/-3) openlp/plugins/bibles/bibleplugin.py (+1/-0) openlp/plugins/bibles/endpoint.py (+2/-1) openlp/plugins/bibles/forms/bibleimportform.py (+7/-6) openlp/plugins/bibles/forms/booknamedialog.py (+3/-3) openlp/plugins/bibles/forms/booknameform.py (+2/-1) openlp/plugins/bibles/forms/editbibledialog.py (+5/-5) openlp/plugins/bibles/forms/editbibleform.py (+3/-1) openlp/plugins/bibles/forms/languagedialog.py (+3/-3) openlp/plugins/bibles/forms/languageform.py (+2/-1) openlp/plugins/bibles/lib/biblestab.py (+6/-5) openlp/plugins/bibles/lib/db.py (+4/-3) openlp/plugins/bibles/lib/importers/csvbible.py (+1/-0) openlp/plugins/bibles/lib/importers/http.py (+1/-0) openlp/plugins/bibles/lib/importers/osis.py (+1/-0) openlp/plugins/bibles/lib/importers/sword.py (+1/-0) openlp/plugins/bibles/lib/importers/wordproject.py (+2/-1) openlp/plugins/bibles/lib/importers/zefania.py (+1/-0) openlp/plugins/bibles/lib/manager.py (+2/-0) openlp/plugins/bibles/lib/mediaitem.py (+7/-7) openlp/plugins/bibles/lib/upgrade.py (+1/-0) openlp/plugins/custom/customplugin.py (+3/-2) openlp/plugins/custom/endpoint.py (+2/-1) openlp/plugins/custom/forms/editcustomdialog.py (+4/-4) openlp/plugins/custom/forms/editcustomform.py (+1/-1) openlp/plugins/custom/forms/editcustomslidedialog.py (+3/-3) openlp/plugins/custom/forms/editcustomslideform.py (+2/-1) openlp/plugins/custom/lib/customtab.py (+3/-3) openlp/plugins/custom/lib/customxmlhandler.py (+1/-0) openlp/plugins/custom/lib/mediaitem.py (+5/-4) openlp/plugins/images/endpoint.py (+2/-1) openlp/plugins/images/forms/__init__.py (+1/-1) openlp/plugins/images/forms/addgroupdialog.py (+3/-3) openlp/plugins/images/forms/addgroupform.py (+1/-1) openlp/plugins/images/forms/choosegroupdialog.py (+3/-3) openlp/plugins/images/forms/choosegroupform.py (+1/-1) openlp/plugins/images/imageplugin.py (+3/-2) openlp/plugins/images/lib/imagetab.py (+3/-3) openlp/plugins/images/lib/mediaitem.py (+5/-5) openlp/plugins/images/lib/upgrade.py (+1/-0) openlp/plugins/media/endpoint.py (+2/-1) openlp/plugins/media/forms/mediaclipselectordialog.py (+3/-3) openlp/plugins/media/forms/mediaclipselectorform.py (+3/-2) openlp/plugins/media/lib/mediaitem.py (+4/-3) openlp/plugins/media/lib/mediatab.py (+3/-3) openlp/plugins/media/mediaplugin.py (+3/-0) openlp/plugins/presentations/endpoint.py (+2/-1) openlp/plugins/presentations/lib/impresscontroller.py (+4/-3) openlp/plugins/presentations/lib/mediaitem.py (+5/-5) openlp/plugins/presentations/lib/messagelistener.py (+1/-0) openlp/plugins/presentations/lib/pdfcontroller.py (+3/-2) openlp/plugins/presentations/lib/powerpointcontroller.py (+21/-10) openlp/plugins/presentations/lib/presentationcontroller.py (+1/-0) openlp/plugins/presentations/lib/presentationtab.py (+3/-3) openlp/plugins/presentations/presentationplugin.py (+2/-1) openlp/plugins/songs/endpoint.py (+2/-1) openlp/plugins/songs/forms/__init__.py (+1/-1) openlp/plugins/songs/forms/authorsdialog.py (+3/-3) openlp/plugins/songs/forms/authorsform.py (+1/-1) openlp/plugins/songs/forms/duplicatesongremovalform.py (+2/-1) openlp/plugins/songs/forms/editsongdialog.py (+4/-4) openlp/plugins/songs/forms/editsongform.py (+6/-5) openlp/plugins/songs/forms/editversedialog.py (+3/-3) openlp/plugins/songs/forms/editverseform.py (+2/-1) openlp/plugins/songs/forms/mediafilesdialog.py (+3/-3) openlp/plugins/songs/forms/mediafilesform.py (+2/-1) openlp/plugins/songs/forms/songbookdialog.py (+3/-3) openlp/plugins/songs/forms/songbookform.py (+1/-1) openlp/plugins/songs/forms/songexportform.py (+4/-3) openlp/plugins/songs/forms/songimportform.py (+4/-3) openlp/plugins/songs/forms/songmaintenancedialog.py (+3/-3) openlp/plugins/songs/forms/songmaintenanceform.py (+5/-3) openlp/plugins/songs/forms/songreviewwidget.py (+4/-4) openlp/plugins/songs/forms/songselectform.py (+1/-0) openlp/plugins/songs/forms/topicsdialog.py (+3/-3) openlp/plugins/songs/forms/topicsform.py (+1/-1) openlp/plugins/songs/lib/__init__.py (+2/-2) openlp/plugins/songs/lib/db.py (+2/-2) openlp/plugins/songs/lib/importer.py (+2/-0) openlp/plugins/songs/lib/importers/cclifile.py (+2/-0) openlp/plugins/songs/lib/importers/chordpro.py (+1/-0) openlp/plugins/songs/lib/importers/dreambeam.py (+1/-0) openlp/plugins/songs/lib/importers/easyslides.py (+1/-0) openlp/plugins/songs/lib/importers/easyworship.py (+3/-2) openlp/plugins/songs/lib/importers/foilpresenter.py (+2/-1) openlp/plugins/songs/lib/importers/lyrix.py (+1/-0) openlp/plugins/songs/lib/importers/mediashout.py (+1/-0) openlp/plugins/songs/lib/importers/openlp.py (+4/-2) openlp/plugins/songs/lib/importers/openlyrics.py (+1/-0) openlp/plugins/songs/lib/importers/openoffice.py (+2/-0) openlp/plugins/songs/lib/importers/opensong.py (+1/-0) openlp/plugins/songs/lib/importers/opspro.py (+1/-0) openlp/plugins/songs/lib/importers/powersong.py (+1/-0) openlp/plugins/songs/lib/importers/presentationmanager.py (+1/-1) openlp/plugins/songs/lib/importers/propresenter.py (+1/-0) openlp/plugins/songs/lib/importers/songbeamer.py (+2/-1) openlp/plugins/songs/lib/importers/songimport.py (+3/-2) openlp/plugins/songs/lib/importers/songshowplus.py (+1/-0) openlp/plugins/songs/lib/importers/songsoffellowship.py (+2/-0) openlp/plugins/songs/lib/importers/sundayplus.py (+2/-2) openlp/plugins/songs/lib/importers/videopsalm.py (+1/-0) openlp/plugins/songs/lib/importers/wordsofworship.py (+1/-0) openlp/plugins/songs/lib/importers/worshipassistant.py (+1/-0) openlp/plugins/songs/lib/importers/worshipcenterpro.py (+1/-0) openlp/plugins/songs/lib/importers/zionworx.py (+1/-0) openlp/plugins/songs/lib/mediaitem.py (+5/-4) openlp/plugins/songs/lib/openlyricsexport.py (+1/-0) openlp/plugins/songs/lib/openlyricsxml.py (+1/-0) openlp/plugins/songs/lib/songselect.py (+1/-0) openlp/plugins/songs/lib/songstab.py (+3/-3) openlp/plugins/songs/lib/upgrade.py (+3/-2) openlp/plugins/songs/reporting.py (+1/-0) openlp/plugins/songs/songsplugin.py (+5/-5) openlp/plugins/songusage/forms/songusagedeletedialog.py (+3/-3) openlp/plugins/songusage/forms/songusagedeleteform.py (+1/-1) openlp/plugins/songusage/forms/songusagedetaildialog.py (+3/-3) openlp/plugins/songusage/forms/songusagedetailform.py (+3/-1) openlp/plugins/songusage/lib/upgrade.py (+2/-1) openlp/plugins/songusage/songusageplugin.py (+3/-2) package.json (+25/-0) run_openlp.py (+3/-1) scripts/appveyor-webhook.py (+5/-4) scripts/appveyor.yml (+4/-10) scripts/check_dependencies.py (+1/-2) scripts/clean_up_resources.py (+1/-0) scripts/jenkins_script.py (+2/-1) scripts/lp-merge.py (+5/-4) scripts/mp_update.py (+3/-1) scripts/reveal-js.patch (+25/-0) scripts/translation_utils.py (+3/-3) scripts/websocket_client.py (+2/-1) setup.cfg (+1/-2) setup.py (+2/-1) tests/functional/openlp_core/api/endpoint/test_controller.py (+35/-13) tests/functional/openlp_core/api/endpoint/test_remote.py (+1/-1) tests/functional/openlp_core/api/http/test_init.py (+1/-2) tests/functional/openlp_core/api/http/test_wsgiapp.py (+1/-0) tests/functional/openlp_core/api/test_deploy.py (+7/-4) tests/functional/openlp_core/api/test_tab.py (+1/-0) tests/functional/openlp_core/api/test_websockets.py (+1/-0) tests/functional/openlp_core/common/test_actions.py (+123/-128) tests/functional/openlp_core/common/test_applocation.py (+1/-0) tests/functional/openlp_core/common/test_common.py (+2/-2) tests/functional/openlp_core/common/test_db.py (+1/-1) tests/functional/openlp_core/common/test_path.py (+2/-2) tests/functional/openlp_core/display/test_render.py (+210/-0) tests/functional/openlp_core/display/test_renderer.py (+0/-208) tests/functional/openlp_core/display/test_screens.py (+66/-18) tests/functional/openlp_core/lib/test_db.py (+2/-2) tests/functional/openlp_core/lib/test_formattingtags.py (+1/-0) tests/functional/openlp_core/lib/test_htmlbuilder.py (+4/-13) tests/functional/openlp_core/lib/test_image_manager.py (+2/-1) tests/functional/openlp_core/lib/test_lib.py (+3/-177) tests/functional/openlp_core/lib/test_serviceitem.py (+35/-55) tests/functional/openlp_core/lib/test_ui.py (+4/-4) tests/functional/openlp_core/test_app.py (+3/-0) tests/functional/openlp_core/test_server.py (+6/-5) tests/functional/openlp_core/test_threading.py (+1/-1) tests/functional/openlp_core/ui/media/test_systemplayer.py (+1/-1) tests/functional/openlp_core/ui/media/test_vlcplayer.py (+1/-1) tests/functional/openlp_core/ui/media/test_webkitplayer.py (+0/-66) tests/functional/openlp_core/ui/test_exceptionform.py (+42/-56) tests/functional/openlp_core/ui/test_firsttimeform.py (+63/-38) tests/functional/openlp_core/ui/test_formattingtagsform.py (+1/-1) tests/functional/openlp_core/ui/test_icons.py (+0/-1) tests/functional/openlp_core/ui/test_maindisplay.py (+0/-283) tests/functional/openlp_core/ui/test_mainwindow.py (+23/-14) tests/functional/openlp_core/ui/test_servicemanager.py (+15/-12) tests/functional/openlp_core/ui/test_slidecontroller.py (+17/-21) tests/functional/openlp_core/widgets/test_views.py (+15/-16) tests/functional/openlp_core/widgets/test_widgets.py (+199/-0) tests/functional/openlp_plugins/bibles/test_bibleimport.py (+1/-1) tests/functional/openlp_plugins/bibles/test_bibleserver.py (+1/-1) tests/functional/openlp_plugins/bibles/test_csvimport.py (+1/-0) tests/functional/openlp_plugins/bibles/test_mediaitem.py (+2/-2) tests/functional/openlp_plugins/bibles/test_opensongimport.py (+2/-1) tests/functional/openlp_plugins/bibles/test_osisimport.py (+1/-0) tests/functional/openlp_plugins/bibles/test_swordimport.py (+5/-3) tests/functional/openlp_plugins/bibles/test_wordprojectimport.py (+2/-1) tests/functional/openlp_plugins/bibles/test_zefaniaimport.py (+1/-0) tests/functional/openlp_plugins/custom/test_mediaitem.py (+2/-1) tests/functional/openlp_plugins/images/test_imagetab.py (+1/-0) tests/functional/openlp_plugins/images/test_upgrade.py (+1/-0) tests/functional/openlp_plugins/media/test_mediaitem.py (+1/-0) tests/functional/openlp_plugins/presentations/test_impresscontroller.py (+3/-3) tests/functional/openlp_plugins/presentations/test_mediaitem.py (+1/-1) tests/functional/openlp_plugins/presentations/test_messagelistener.py (+1/-1) tests/functional/openlp_plugins/presentations/test_pdfcontroller.py (+5/-5) tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py (+3/-2) tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py.THIS (+224/-0) tests/functional/openlp_plugins/presentations/test_presentationcontroller.py (+1/-0) tests/functional/openlp_plugins/songs/test_chordproimport.py (+2/-1) tests/functional/openlp_plugins/songs/test_db.py (+1/-1) tests/functional/openlp_plugins/songs/test_easyslidesimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_editsongform.py (+1/-1) tests/functional/openlp_plugins/songs/test_editverseform.py (+1/-0) tests/functional/openlp_plugins/songs/test_ewimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_foilpresenterimport.py (+1/-1) tests/functional/openlp_plugins/songs/test_lib.py (+2/-2) tests/functional/openlp_plugins/songs/test_lyriximport.py (+1/-0) tests/functional/openlp_plugins/songs/test_mediashout.py (+2/-1) tests/functional/openlp_plugins/songs/test_openlpimporter.py (+1/-1) tests/functional/openlp_plugins/songs/test_openlyricsimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_openoffice.py (+1/-0) tests/functional/openlp_plugins/songs/test_opensongimport.py (+2/-1) tests/functional/openlp_plugins/songs/test_opsproimport.py (+5/-3) tests/functional/openlp_plugins/songs/test_powerpraiseimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_propresenterimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_songbeamerimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_songproimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_songselect.py (+4/-3) tests/functional/openlp_plugins/songs/test_songshowplusimport.py (+2/-1) tests/functional/openlp_plugins/songs/test_sundayplusimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_videopsalm.py (+2/-1) tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_worshipassistantimport.py (+1/-0) tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py (+3/-2) tests/functional/openlp_plugins/songs/test_zionworximport.py (+1/-0) tests/helpers/songfileimport.py (+2/-1) tests/interfaces/openlp_core/common/test_utils.py (+0/-1) tests/interfaces/openlp_core/ui/test_servicemanager.py (+3/-3) tests/interfaces/openlp_core/ui/test_settings_form.py (+1/-0) tests/interfaces/openlp_core/ui/test_thememanager.py (+1/-1) tests/interfaces/openlp_core/widgets/test_edits.py (+1/-1) tests/interfaces/openlp_core/widgets/test_views.py (+5/-0) tests/interfaces/openlp_plugins/bibles/test_lib_http.py (+1/-1) tests/interfaces/openlp_plugins/custom/forms/test_customform.py (+1/-1) tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py (+9/-7) tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py (+1/-0) tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py (+1/-0) tests/interfaces/openlp_plugins/songs/forms/test_songmaintenanceform.py (+1/-1) tests/js/fake_webchannel.js (+5/-0) tests/js/polyfill.js (+84/-0) tests/js/test_display.js (+632/-0) tests/openlp_core/common/test_network_interfaces.py (+0/-1) tests/openlp_core/projectors/test_projector_bugfixes_01.py (+1/-0) tests/openlp_core/projectors/test_projector_constants.py (+1/-0) tests/openlp_core/projectors/test_projector_db.py (+1/-1) tests/openlp_core/projectors/test_projector_editform.py (+1/-1) tests/openlp_core/projectors/test_projector_pjlink_base_01.py (+3/-5) tests/openlp_core/projectors/test_projector_pjlink_base_02.py (+0/-1) tests/openlp_core/projectors/test_projector_pjlink_cmd_routing.py (+2/-3) tests/openlp_core/projectors/test_projector_pjlink_commands_01.py (+2/-12) tests/openlp_core/projectors/test_projector_pjlink_commands_02.py (+2/-2) tests/openlp_core/projectors/test_projector_pjlink_udp.py (+1/-1) tests/openlp_core/projectors/test_projector_sourceform.py (+3/-3) tests/openlp_core/projectors/test_projector_utilities.py (+3/-2) tests/openlp_core/projectors/test_projectormanager.py (+1/-1) tests/utils/__init__.py (+7/-10) tests/utils/constants.py (+1/-0) tests/utils/test_bzr_tags.py (+2/-1) tests/utils/test_pylint.py (+4/-2) |
To merge this branch: | bzr merge lp:~openlp-dev/openlp/webengine-migrate |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenLP Core | Pending | ||
Review via email: mp+363088@code.launchpad.net |
This proposal supersedes a proposal from 2019-02-12.
This proposal has been superseded by a proposal from 2019-02-12.
Commit message
Migration from WebKit to Webengine. Also introduced reveal.js for slide rendering, new screen setup dialogs and many other changes.
Description of the change
To post a comment you must log in.
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : Posted in a previous version of this proposal | # |
Linux tests failed, please see https:/
Revision history for this message
Raoul Snyman (raoul-snyman) wrote : | # |
Linux tests failed, please see https:/
- 2878. By Tim Bentley
-
fix up tests
- 2879. By Tomas Groth
-
Fix more tests
- 2880. By Tomas Groth
-
pep8 fixes
- 2881. By Tomas Groth
-
More pep8 fixes
- 2882. By Tomas Groth
-
Even more pep8 fixes and removed the old htmlbuilder.
- 2883. By Raoul Snyman
-
Fix an unused import and some incorrect patch()s
- 2884. By Raoul Snyman
-
HEAD
- 2885. By Tomas Groth
-
trunk
Unmerged revisions
- 2885. By Tomas Groth
-
trunk
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2018-06-26 17:10:34 +0000 |
3 | +++ .bzrignore 2019-02-12 20:56:20 +0000 |
4 | @@ -45,4 +45,11 @@ |
5 | resources/windows/warnOpenLP.txt |
6 | *.ropeproject |
7 | tags |
8 | +output |
9 | +htmlcov |
10 | +node_modules |
11 | +openlp-test-projectordb.sqlite |
12 | +package-lock.json |
13 | +.cache |
14 | +test |
15 | tests.kdev4 |
16 | |
17 | === added file 'karma.conf.js' |
18 | --- karma.conf.js 1970-01-01 00:00:00 +0000 |
19 | +++ karma.conf.js 2019-02-12 20:56:20 +0000 |
20 | @@ -0,0 +1,77 @@ |
21 | +module.exports = function(config) { |
22 | + config.set({ |
23 | + // base path that will be used to resolve all patterns (eg. files, exclude) |
24 | + basePath: "", |
25 | + |
26 | + // frameworks to use |
27 | + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter |
28 | + frameworks: ["jasmine"], |
29 | + |
30 | + // list of files / patterns to load in the browser |
31 | + files: [ |
32 | + "tests/js/polyfill.js", |
33 | + "tests/js/fake_webchannel.js", |
34 | + "openlp/core/display/html/reveal.js", |
35 | + "openlp/core/display/html/display.js", |
36 | + "tests/js/test_*.js" |
37 | + ], |
38 | + |
39 | + // list of files to exclude |
40 | + exclude: [ |
41 | + ], |
42 | + |
43 | + // preprocess matching files before serving them to the browser |
44 | + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor |
45 | + preprocessors: { |
46 | + // source files, that you wanna generate coverage for |
47 | + // do not include tests or libraries |
48 | + // (these files will be instrumented by Istanbul) |
49 | + "display.js": ["coverage"] |
50 | + }, |
51 | + |
52 | + // test results reporter to use |
53 | + // possible values: "dots", "progress" |
54 | + // available reporters: https://npmjs.org/browse/keyword/karma-reporter |
55 | + reporters: ["progress", "coverage"], |
56 | + |
57 | + // configure the coverateReporter |
58 | + coverageReporter: { |
59 | + type : "html", |
60 | + dir : "htmlcov/" |
61 | + }, |
62 | + |
63 | + // web server port |
64 | + port: 9876, |
65 | + |
66 | + // enable / disable colors in the output (reporters and logs) |
67 | + colors: true, |
68 | + |
69 | + // level of logging |
70 | + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG |
71 | + logLevel: config.LOG_DEBUG, |
72 | + |
73 | + // loggers |
74 | + /* loggers: [ |
75 | + {"type": "file", "filename": "karma.log"} |
76 | + ],*/ |
77 | + |
78 | + // enable / disable watching file and executing tests whenever any file changes |
79 | + autoWatch: true, |
80 | + |
81 | + // start these browsers |
82 | + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher |
83 | + browsers: ["PhantomJS"], |
84 | + |
85 | + // Continuous Integration mode |
86 | + // if true, Karma captures browsers, runs the tests and exits |
87 | + singleRun: false, |
88 | + |
89 | + // Concurrency level |
90 | + // how many browser should be started simultaneous |
91 | + concurrency: Infinity, |
92 | + |
93 | + client: { |
94 | + captureConsole: true |
95 | + } |
96 | + }) |
97 | +} |
98 | |
99 | === modified file 'nose2.cfg' |
100 | --- nose2.cfg 2017-11-16 05:03:19 +0000 |
101 | +++ nose2.cfg 2019-02-12 20:56:20 +0000 |
102 | @@ -1,5 +1,5 @@ |
103 | [unittest] |
104 | -verbose = True |
105 | +verbose = true |
106 | plugins = nose2.plugins.mp |
107 | |
108 | [log-capture] |
109 | @@ -9,19 +9,19 @@ |
110 | log-level = ERROR |
111 | |
112 | [test-result] |
113 | -always-on = True |
114 | -descriptions = True |
115 | +always-on = true |
116 | +descriptions = true |
117 | |
118 | [coverage] |
119 | -always-on = True |
120 | +always-on = true |
121 | coverage = openlp |
122 | coverage-report = html |
123 | |
124 | [multiprocess] |
125 | -always-on = False |
126 | +always-on = false |
127 | processes = 4 |
128 | |
129 | [output-buffer] |
130 | -always-on = True |
131 | -stderr = True |
132 | -stdout = False |
133 | +always-on = true |
134 | +stderr = true |
135 | +stdout = true |
136 | |
137 | === modified file 'openlp/.version' |
138 | --- openlp/.version 2019-01-11 20:23:24 +0000 |
139 | +++ openlp/.version 2019-02-12 20:56:20 +0000 |
140 | @@ -1,1 +1,1 @@ |
141 | -2.9.0 |
142 | +2.5.dev2856 |
143 | \ No newline at end of file |
144 | |
145 | === modified file 'openlp/core/api/deploy.py' |
146 | --- openlp/core/api/deploy.py 2018-01-04 07:00:55 +0000 |
147 | +++ openlp/core/api/deploy.py 2019-02-12 20:56:20 +0000 |
148 | @@ -25,7 +25,7 @@ |
149 | from zipfile import ZipFile |
150 | |
151 | from openlp.core.common.applocation import AppLocation |
152 | -from openlp.core.common.httputils import download_file, get_web_page, get_url_file_size |
153 | +from openlp.core.common.httputils import download_file, get_url_file_size, get_web_page |
154 | from openlp.core.common.registry import Registry |
155 | |
156 | |
157 | |
158 | === modified file 'openlp/core/api/endpoint/controller.py' |
159 | --- openlp/core/api/endpoint/controller.py 2018-08-25 14:08:19 +0000 |
160 | +++ openlp/core/api/endpoint/controller.py 2019-02-12 20:56:20 +0000 |
161 | @@ -34,6 +34,7 @@ |
162 | from openlp.core.lib import create_thumb |
163 | from openlp.core.lib.serviceitem import ItemCapabilities |
164 | |
165 | + |
166 | log = logging.getLogger(__name__) |
167 | |
168 | controller_endpoint = Endpoint('controller') |
169 | @@ -48,7 +49,7 @@ |
170 | |
171 | :param request: the http request - not used |
172 | """ |
173 | - log.debug("controller_text ") |
174 | + log.debug('controller_text') |
175 | live_controller = Registry().get('live_controller') |
176 | current_item = live_controller.service_item |
177 | data = [] |
178 | @@ -57,13 +58,14 @@ |
179 | item = {} |
180 | # Handle text (songs, custom, bibles) |
181 | if current_item.is_text(): |
182 | - if frame['verseTag']: |
183 | - item['tag'] = str(frame['verseTag']) |
184 | + if frame['verse']: |
185 | + item['tag'] = str(frame['verse']) |
186 | else: |
187 | item['tag'] = str(index + 1) |
188 | - item['chords_text'] = str(frame['chords_text']) |
189 | - item['text'] = str(frame['text']) |
190 | - item['html'] = str(frame['html']) |
191 | + # TODO: Figure out rendering chords |
192 | + item['chords_text'] = str(frame.get('chords_text', '')) |
193 | + item['text'] = frame['text'] |
194 | + item['html'] = current_item.get_rendered_frame(index) |
195 | # Handle images, unless a custom thumbnail is given or if thumbnails is disabled |
196 | elif current_item.is_image() and not frame.get('image', '') and Settings().value('api/thumbnails'): |
197 | item['tag'] = str(index + 1) |
198 | |
199 | === modified file 'openlp/core/api/endpoint/core.py' |
200 | --- openlp/core/api/endpoint/core.py 2018-08-25 14:08:19 +0000 |
201 | +++ openlp/core/api/endpoint/core.py 2019-02-12 20:56:20 +0000 |
202 | @@ -30,8 +30,8 @@ |
203 | from openlp.core.common.i18n import UiStrings, translate |
204 | from openlp.core.common.registry import Registry |
205 | from openlp.core.lib import image_to_byte |
206 | -from openlp.core.lib.plugin import StringContent |
207 | -from openlp.core.lib.plugin import PluginStatus |
208 | +from openlp.core.lib.plugin import PluginStatus, StringContent |
209 | + |
210 | |
211 | template_dir = 'templates' |
212 | static_dir = 'static' |
213 | |
214 | === modified file 'openlp/core/api/endpoint/remote.py' |
215 | --- openlp/core/api/endpoint/remote.py 2017-12-29 09:15:48 +0000 |
216 | +++ openlp/core/api/endpoint/remote.py 2019-02-12 20:56:20 +0000 |
217 | @@ -24,6 +24,7 @@ |
218 | from openlp.core.api.endpoint.core import TRANSLATED_STRINGS |
219 | from openlp.core.api.http.endpoint import Endpoint |
220 | |
221 | + |
222 | log = logging.getLogger(__name__) |
223 | |
224 | remote_endpoint = Endpoint('remote', template_dir='remotes') |
225 | |
226 | === modified file 'openlp/core/api/endpoint/service.py' |
227 | --- openlp/core/api/endpoint/service.py 2017-12-29 09:15:48 +0000 |
228 | +++ openlp/core/api/endpoint/service.py 2019-02-12 20:56:20 +0000 |
229 | @@ -26,6 +26,7 @@ |
230 | from openlp.core.api.http.endpoint import Endpoint |
231 | from openlp.core.common.registry import Registry |
232 | |
233 | + |
234 | log = logging.getLogger(__name__) |
235 | |
236 | service_endpoint = Endpoint('service') |
237 | |
238 | === modified file 'openlp/core/api/http/server.py' |
239 | --- openlp/core/api/http/server.py 2018-01-07 04:36:45 +0000 |
240 | +++ openlp/core/api/http/server.py 2019-02-12 20:56:20 +0000 |
241 | @@ -30,22 +30,21 @@ |
242 | from waitress.server import create_server |
243 | |
244 | from openlp.core.api.deploy import download_and_check, download_sha256 |
245 | -from openlp.core.api.endpoint.controller import controller_endpoint, api_controller_endpoint |
246 | -from openlp.core.api.endpoint.core import chords_endpoint, stage_endpoint, blank_endpoint, main_endpoint |
247 | +from openlp.core.api.endpoint.controller import api_controller_endpoint, controller_endpoint |
248 | +from openlp.core.api.endpoint.core import blank_endpoint, chords_endpoint, main_endpoint, stage_endpoint |
249 | from openlp.core.api.endpoint.remote import remote_endpoint |
250 | -from openlp.core.api.endpoint.service import service_endpoint, api_service_endpoint |
251 | -from openlp.core.api.http import application |
252 | -from openlp.core.api.http import register_endpoint |
253 | +from openlp.core.api.endpoint.service import api_service_endpoint, service_endpoint |
254 | +from openlp.core.api.http import application, register_endpoint |
255 | from openlp.core.api.poll import Poller |
256 | from openlp.core.common.applocation import AppLocation |
257 | -from openlp.core.common.i18n import UiStrings |
258 | -from openlp.core.common.i18n import translate |
259 | +from openlp.core.common.i18n import UiStrings, translate |
260 | from openlp.core.common.mixins import LogMixin, RegistryProperties |
261 | from openlp.core.common.path import create_paths |
262 | from openlp.core.common.registry import Registry, RegistryBase |
263 | from openlp.core.common.settings import Settings |
264 | from openlp.core.threading import ThreadWorker, run_thread |
265 | |
266 | + |
267 | log = logging.getLogger(__name__) |
268 | |
269 | |
270 | |
271 | === modified file 'openlp/core/api/http/wsgiapp.py' |
272 | --- openlp/core/api/http/wsgiapp.py 2018-07-04 20:42:55 +0000 |
273 | +++ openlp/core/api/http/wsgiapp.py 2019-02-12 20:56:20 +0000 |
274 | @@ -33,6 +33,7 @@ |
275 | from openlp.core.api.http.errors import HttpError, NotFound, ServerError |
276 | from openlp.core.common.applocation import AppLocation |
277 | |
278 | + |
279 | ARGS_REGEX = re.compile(r'''\{(\w+)(?::([^}]+))?\}''', re.VERBOSE) |
280 | |
281 | log = logging.getLogger(__name__) |
282 | |
283 | === modified file 'openlp/core/api/tab.py' |
284 | --- openlp/core/api/tab.py 2018-08-25 14:08:19 +0000 |
285 | +++ openlp/core/api/tab.py 2019-02-12 20:56:20 +0000 |
286 | @@ -31,6 +31,7 @@ |
287 | from openlp.core.lib.settingstab import SettingsTab |
288 | from openlp.core.ui.icons import UiIcons |
289 | |
290 | + |
291 | ZERO_URL = '0.0.0.0' |
292 | |
293 | |
294 | @@ -43,9 +44,9 @@ |
295 | advanced_translated = translate('OpenLP.AdvancedTab', 'Advanced') |
296 | super(ApiTab, self).__init__(parent, 'api', advanced_translated) |
297 | |
298 | - def setupUi(self): |
299 | + def setup_ui(self): |
300 | self.setObjectName('ApiTab') |
301 | - super(ApiTab, self).setupUi() |
302 | + super(ApiTab, self).setup_ui() |
303 | self.server_settings_group_box = QtWidgets.QGroupBox(self.left_column) |
304 | self.server_settings_group_box.setObjectName('server_settings_group_box') |
305 | self.server_settings_layout = QtWidgets.QFormLayout(self.server_settings_group_box) |
306 | @@ -154,7 +155,7 @@ |
307 | self.thumbnails_check_box.stateChanged.connect(self.on_thumbnails_check_box_changed) |
308 | self.address_edit.textChanged.connect(self.set_urls) |
309 | |
310 | - def retranslateUi(self): |
311 | + def retranslate_ui(self): |
312 | self.tab_title_visible = translate('RemotePlugin.RemoteTab', 'Remote Interface') |
313 | self.server_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Server Settings')) |
314 | self.address_label.setText(translate('RemotePlugin.RemoteTab', 'Serve on IP address:')) |
315 | |
316 | === modified file 'openlp/core/api/websockets.py' |
317 | --- openlp/core/api/websockets.py 2018-01-07 17:50:29 +0000 |
318 | +++ openlp/core/api/websockets.py 2019-02-12 20:56:20 +0000 |
319 | @@ -35,6 +35,7 @@ |
320 | from openlp.core.common.settings import Settings |
321 | from openlp.core.threading import ThreadWorker, run_thread |
322 | |
323 | + |
324 | log = logging.getLogger(__name__) |
325 | |
326 | |
327 | |
328 | === modified file 'openlp/core/app.py' |
329 | --- openlp/core/app.py 2018-10-25 16:38:39 +0000 |
330 | +++ openlp/core/app.py 2019-02-12 20:56:20 +0000 |
331 | @@ -33,27 +33,28 @@ |
332 | from datetime import datetime |
333 | from traceback import format_exception |
334 | |
335 | -from PyQt5 import QtCore, QtWidgets |
336 | +from PyQt5 import QtCore, QtWebEngineWidgets, QtWidgets # noqa |
337 | |
338 | from openlp.core.state import State |
339 | from openlp.core.common import is_macosx, is_win |
340 | from openlp.core.common.applocation import AppLocation |
341 | from openlp.core.loader import loader |
342 | from openlp.core.common.i18n import LanguageManager, UiStrings, translate |
343 | -from openlp.core.common.path import create_paths, copytree |
344 | +from openlp.core.common.path import copytree, create_paths |
345 | from openlp.core.common.registry import Registry |
346 | from openlp.core.common.settings import Settings |
347 | from openlp.core.display.screens import ScreenList |
348 | from openlp.core.resources import qInitResources |
349 | -from openlp.core.ui.splashscreen import SplashScreen |
350 | +from openlp.core.server import Server |
351 | from openlp.core.ui.exceptionform import ExceptionForm |
352 | from openlp.core.ui.firsttimeform import FirstTimeForm |
353 | from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm |
354 | from openlp.core.ui.mainwindow import MainWindow |
355 | +from openlp.core.ui.splashscreen import SplashScreen |
356 | from openlp.core.ui.style import get_application_stylesheet |
357 | -from openlp.core.server import Server |
358 | from openlp.core.version import check_for_update, get_version |
359 | |
360 | + |
361 | __all__ = ['OpenLP', 'main'] |
362 | |
363 | |
364 | @@ -74,7 +75,8 @@ |
365 | """ |
366 | self.is_event_loop_active = True |
367 | result = QtWidgets.QApplication.exec() |
368 | - self.server.close_server() |
369 | + if hasattr(self, 'server'): |
370 | + self.server.close_server() |
371 | return result |
372 | |
373 | def run(self, args): |
374 | @@ -317,7 +319,7 @@ |
375 | file_path = log_path / 'openlp.log' |
376 | # TODO: FileHandler accepts a Path object in Py3.6 |
377 | logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8') |
378 | - logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s')) |
379 | + logfile.setFormatter(logging.Formatter('%(asctime)s %(threadName)s %(name)-55s %(levelname)-8s %(message)s')) |
380 | log.addHandler(logfile) |
381 | if log.isEnabledFor(logging.DEBUG): |
382 | print('Logging to: {name}'.format(name=file_path)) |
383 | @@ -330,7 +332,8 @@ |
384 | :param args: Some args |
385 | """ |
386 | args = parse_options(args) |
387 | - qt_args = [] |
388 | + qt_args = ['--disable-web-security'] |
389 | + # qt_args = [] |
390 | if args and args.loglevel.lower() in ['d', 'debug']: |
391 | log.setLevel(logging.DEBUG) |
392 | elif args and args.loglevel.lower() in ['w', 'warning']: |
393 | |
394 | === modified file 'openlp/core/common/actions.py' |
395 | --- openlp/core/common/actions.py 2018-10-13 10:24:01 +0000 |
396 | +++ openlp/core/common/actions.py 2019-02-12 20:56:20 +0000 |
397 | @@ -29,6 +29,7 @@ |
398 | |
399 | from openlp.core.common.settings import Settings |
400 | |
401 | + |
402 | log = logging.getLogger(__name__) |
403 | |
404 | |
405 | @@ -113,7 +114,6 @@ |
406 | if item[1] == action: |
407 | self.actions.remove(item) |
408 | return |
409 | - log.warning('Action "{action}" does not exist.'.format(action=action)) |
410 | |
411 | |
412 | class CategoryList(object): |
413 | |
414 | === modified file 'openlp/core/common/applocation.py' |
415 | --- openlp/core/common/applocation.py 2018-10-07 23:34:00 +0000 |
416 | +++ openlp/core/common/applocation.py 2019-02-12 20:56:20 +0000 |
417 | @@ -29,10 +29,11 @@ |
418 | import appdirs |
419 | |
420 | import openlp |
421 | -from openlp.core.common import get_frozen_path, is_win, is_macosx |
422 | +from openlp.core.common import get_frozen_path, is_macosx, is_win |
423 | from openlp.core.common.path import Path, create_paths |
424 | from openlp.core.common.settings import Settings |
425 | |
426 | + |
427 | log = logging.getLogger(__name__) |
428 | |
429 | FROZEN_APP_PATH = Path(sys.argv[0]).parent |
430 | |
431 | === modified file 'openlp/core/common/db.py' |
432 | --- openlp/core/common/db.py 2017-12-29 09:15:48 +0000 |
433 | +++ openlp/core/common/db.py 2019-02-12 20:56:20 +0000 |
434 | @@ -27,6 +27,7 @@ |
435 | |
436 | import sqlalchemy |
437 | |
438 | + |
439 | log = logging.getLogger(__name__) |
440 | |
441 | |
442 | |
443 | === modified file 'openlp/core/common/httputils.py' |
444 | --- openlp/core/common/httputils.py 2018-06-08 20:55:20 +0000 |
445 | +++ openlp/core/common/httputils.py 2019-02-12 20:56:20 +0000 |
446 | @@ -34,6 +34,7 @@ |
447 | from openlp.core.common.registry import Registry |
448 | from openlp.core.common.settings import ProxyMode, Settings |
449 | |
450 | + |
451 | log = logging.getLogger(__name__ + '.__init__') |
452 | |
453 | USER_AGENTS = { |
454 | |
455 | === modified file 'openlp/core/common/i18n.py' |
456 | --- openlp/core/common/i18n.py 2018-10-27 11:05:41 +0000 |
457 | +++ openlp/core/common/i18n.py 2019-02-12 20:56:20 +0000 |
458 | @@ -29,10 +29,11 @@ |
459 | |
460 | from PyQt5 import QtCore, QtWidgets |
461 | |
462 | -from openlp.core.common import is_win, is_macosx |
463 | +from openlp.core.common import is_macosx, is_win |
464 | from openlp.core.common.applocation import AppLocation |
465 | from openlp.core.common.settings import Settings |
466 | |
467 | + |
468 | log = logging.getLogger(__name__) |
469 | |
470 | |
471 | |
472 | === modified file 'openlp/core/common/mixins.py' |
473 | --- openlp/core/common/mixins.py 2018-11-18 17:29:47 +0000 |
474 | +++ openlp/core/common/mixins.py 2019-02-12 20:56:20 +0000 |
475 | @@ -28,6 +28,7 @@ |
476 | from openlp.core.common import is_win, trace_error_handler |
477 | from openlp.core.common.registry import Registry |
478 | |
479 | + |
480 | DO_NOT_TRACE_EVENTS = ['timerEvent', 'paintEvent', 'drag_enter_event', 'drop_event', 'on_controller_size_changed', |
481 | 'preview_size_changed', 'resizeEvent'] |
482 | |
483 | |
484 | === modified file 'openlp/core/common/path.py' |
485 | --- openlp/core/common/path.py 2018-08-12 11:14:47 +0000 |
486 | +++ openlp/core/common/path.py 2019-02-12 20:56:20 +0000 |
487 | @@ -25,6 +25,7 @@ |
488 | |
489 | from openlp.core.common import is_win |
490 | |
491 | + |
492 | if is_win(): |
493 | from pathlib import WindowsPath as PathVariant # pragma: nocover |
494 | else: |
495 | |
496 | === modified file 'openlp/core/common/registry.py' |
497 | --- openlp/core/common/registry.py 2018-10-25 16:38:39 +0000 |
498 | +++ openlp/core/common/registry.py 2019-02-12 20:56:20 +0000 |
499 | @@ -27,6 +27,7 @@ |
500 | |
501 | from openlp.core.common import de_hump, trace_error_handler |
502 | |
503 | + |
504 | log = logging.getLogger(__name__) |
505 | |
506 | |
507 | @@ -143,6 +144,7 @@ |
508 | if event in self.functions_list: |
509 | for function in self.functions_list[event]: |
510 | try: |
511 | + log.debug('Running function {} for {}'.format(function, event)) |
512 | result = function(*args, **kwargs) |
513 | if result: |
514 | results.append(result) |
515 | |
516 | === modified file 'openlp/core/common/settings.py' |
517 | --- openlp/core/common/settings.py 2018-10-24 19:35:22 +0000 |
518 | +++ openlp/core/common/settings.py 2019-02-12 20:56:20 +0000 |
519 | @@ -1,4 +1,4 @@ |
520 | -# -*- coding: utf-8 -*- |
521 | + # -*- coding: utf-8 -*- |
522 | # vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 |
523 | |
524 | ############################################################################### |
525 | @@ -33,7 +33,8 @@ |
526 | |
527 | from openlp.core.common import SlideLimits, ThemeLevel, is_linux, is_win |
528 | from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder |
529 | -from openlp.core.common.path import Path, str_to_path, files_to_paths |
530 | +from openlp.core.common.path import Path, files_to_paths, str_to_path |
531 | + |
532 | |
533 | log = logging.getLogger(__name__) |
534 | |
535 | @@ -70,6 +71,34 @@ |
536 | return string |
537 | |
538 | |
539 | +def upgrade_screens(number, x_position, y_position, height, width, can_override, is_display_screen): |
540 | + """ |
541 | + Upgrade them monitor setting from a few single entries to a composite JSON entry |
542 | + |
543 | + :param int number: The old monitor number |
544 | + :param int x_position: The X position |
545 | + :param int y_position: The Y position |
546 | + :param bool can_override: Are the screen positions overridden |
547 | + :param bool is_display_screen: Is this a display screen |
548 | + :returns dict: Dictionary with the new value |
549 | + """ |
550 | + geometry_key = 'geometry' |
551 | + if can_override: |
552 | + geometry_key = 'custom_geometry' |
553 | + return { |
554 | + number: { |
555 | + 'number': number, |
556 | + geometry_key: { |
557 | + 'x': x_position, |
558 | + 'y': y_position, |
559 | + 'height': height, |
560 | + 'width': width |
561 | + }, |
562 | + 'is_display': is_display_screen |
563 | + } |
564 | + } |
565 | + |
566 | + |
567 | class Settings(QtCore.QSettings): |
568 | """ |
569 | Class to wrap QSettings. |
570 | @@ -175,6 +204,7 @@ |
571 | # circular dependency. |
572 | 'core/display on monitor': True, |
573 | 'core/override position': False, |
574 | + 'core/monitor': {}, |
575 | 'core/application version': '0.0', |
576 | 'images/background color': '#000000', |
577 | 'media/players': 'system,webkit', |
578 | @@ -276,6 +306,8 @@ |
579 | ('songuasge/db hostname', 'songusage/db hostname', []), |
580 | ('songuasge/db database', 'songusage/db database', []), |
581 | ('presentations / Powerpoint Viewer', '', []), |
582 | + (['core/monitor', 'core/x position', 'core/y position', 'core/height', 'core/width', 'core/override', |
583 | + 'core/display on monitor'], 'core/screens', [(upgrade_screens, [1, 0, 0, None, None, False, False])]), |
584 | ('bibles/proxy name', '', []), # Just remove these bible proxy settings. They weren't used in 2.4! |
585 | ('bibles/proxy address', '', []), |
586 | ('bibles/proxy username', '', []), |
587 | @@ -545,7 +577,7 @@ |
588 | :param value: The value to save |
589 | :rtype: None |
590 | """ |
591 | - if isinstance(value, Path) or (isinstance(value, list) and value and isinstance(value[0], Path)): |
592 | + if isinstance(value, (Path, dict)) or (isinstance(value, list) and value and isinstance(value[0], Path)): |
593 | value = json.dumps(value, cls=OpenLPJsonEncoder) |
594 | super().setValue(key, value) |
595 | |
596 | @@ -568,8 +600,11 @@ |
597 | # An empty list saved to the settings results in a None type being returned. |
598 | elif isinstance(default_value, list): |
599 | return [] |
600 | + # An empty dictionary saved to the settings results in a None type being returned. |
601 | + elif isinstance(default_value, dict): |
602 | + return {} |
603 | elif isinstance(setting, str): |
604 | - if '__Path__' in setting: |
605 | + if '__Path__' in setting or setting.startswith('{'): |
606 | return json.loads(setting, cls=OpenLPJsonDecoder) |
607 | # Convert the setting to the correct type. |
608 | if isinstance(default_value, bool): |
609 | @@ -578,6 +613,8 @@ |
610 | # Sometimes setting is string instead of a boolean. |
611 | return setting == 'true' |
612 | if isinstance(default_value, int): |
613 | + if setting is None: |
614 | + return 0 |
615 | return int(setting) |
616 | return setting |
617 | |
618 | |
619 | === added directory 'openlp/core/display/html' |
620 | === added file 'openlp/core/display/html/black.css' |
621 | --- openlp/core/display/html/black.css 1970-01-01 00:00:00 +0000 |
622 | +++ openlp/core/display/html/black.css 2019-02-12 20:56:20 +0000 |
623 | @@ -0,0 +1,292 @@ |
624 | +/** |
625 | + * Black theme for reveal.js. This is the opposite of the 'white' theme. |
626 | + * |
627 | + * By Hakim El Hattab, http://hakim.se |
628 | + */ |
629 | +@import url(../../lib/font/source-sans-pro/source-sans-pro.css); |
630 | +section.has-light-background, section.has-light-background h1, section.has-light-background h2, section.has-light-background h3, section.has-light-background h4, section.has-light-background h5, section.has-light-background h6 { |
631 | + color: #222; } |
632 | + |
633 | +/********************************************* |
634 | + * GLOBAL STYLES |
635 | + *********************************************/ |
636 | +body { |
637 | + background: #222; |
638 | + background-color: #222; } |
639 | + |
640 | +.reveal { |
641 | + font-family: "Source Sans Pro", Helvetica, sans-serif; |
642 | + font-size: 42px; |
643 | + font-weight: normal; |
644 | + color: #fff; } |
645 | + |
646 | +::selection { |
647 | + color: #fff; |
648 | + background: #bee4fd; |
649 | + text-shadow: none; } |
650 | + |
651 | +::-moz-selection { |
652 | + color: #fff; |
653 | + background: #bee4fd; |
654 | + text-shadow: none; } |
655 | + |
656 | +.reveal .slides > section, |
657 | +.reveal .slides > section > section { |
658 | + line-height: 1.3; |
659 | + font-weight: inherit; } |
660 | + |
661 | +/********************************************* |
662 | + * HEADERS |
663 | + *********************************************/ |
664 | +.reveal h1, |
665 | +.reveal h2, |
666 | +.reveal h3, |
667 | +.reveal h4, |
668 | +.reveal h5, |
669 | +.reveal h6 { |
670 | + margin: 0 0 20px 0; |
671 | + color: #fff; |
672 | + font-family: "Source Sans Pro", Helvetica, sans-serif; |
673 | + font-weight: 600; |
674 | + line-height: 1.2; |
675 | + letter-spacing: normal; |
676 | + text-transform: uppercase; |
677 | + text-shadow: none; |
678 | + word-wrap: break-word; } |
679 | + |
680 | +.reveal h1 { |
681 | + font-size: 2.5em; } |
682 | + |
683 | +.reveal h2 { |
684 | + font-size: 1.6em; } |
685 | + |
686 | +.reveal h3 { |
687 | + font-size: 1.3em; } |
688 | + |
689 | +.reveal h4 { |
690 | + font-size: 1em; } |
691 | + |
692 | +.reveal h1 { |
693 | + text-shadow: none; } |
694 | + |
695 | +/********************************************* |
696 | + * OTHER |
697 | + *********************************************/ |
698 | +.reveal p { |
699 | + margin: 20px 0; |
700 | + line-height: 1.3; } |
701 | + |
702 | +/* Ensure certain elements are never larger than the slide itself */ |
703 | +.reveal img, |
704 | +.reveal video, |
705 | +.reveal iframe { |
706 | + max-width: 95%; |
707 | + max-height: 95%; } |
708 | + |
709 | +.reveal strong, |
710 | +.reveal b { |
711 | + font-weight: bold; } |
712 | + |
713 | +.reveal em { |
714 | + font-style: italic; } |
715 | + |
716 | +.reveal ol, |
717 | +.reveal dl, |
718 | +.reveal ul { |
719 | + display: inline-block; |
720 | + text-align: left; |
721 | + margin: 0 0 0 1em; } |
722 | + |
723 | +.reveal ol { |
724 | + list-style-type: decimal; } |
725 | + |
726 | +.reveal ul { |
727 | + list-style-type: disc; } |
728 | + |
729 | +.reveal ul ul { |
730 | + list-style-type: square; } |
731 | + |
732 | +.reveal ul ul ul { |
733 | + list-style-type: circle; } |
734 | + |
735 | +.reveal ul ul, |
736 | +.reveal ul ol, |
737 | +.reveal ol ol, |
738 | +.reveal ol ul { |
739 | + display: block; |
740 | + margin-left: 40px; } |
741 | + |
742 | +.reveal dt { |
743 | + font-weight: bold; } |
744 | + |
745 | +.reveal dd { |
746 | + margin-left: 40px; } |
747 | + |
748 | +.reveal q, |
749 | +.reveal blockquote { |
750 | + quotes: none; } |
751 | + |
752 | +.reveal blockquote { |
753 | + display: block; |
754 | + position: relative; |
755 | + width: 70%; |
756 | + margin: 20px auto; |
757 | + padding: 5px; |
758 | + font-style: italic; |
759 | + background: rgba(255, 255, 255, 0.05); |
760 | + box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); } |
761 | + |
762 | +.reveal blockquote p:first-child, |
763 | +.reveal blockquote p:last-child { |
764 | + display: inline-block; } |
765 | + |
766 | +.reveal q { |
767 | + font-style: italic; } |
768 | + |
769 | +.reveal pre { |
770 | + display: block; |
771 | + position: relative; |
772 | + width: 90%; |
773 | + margin: 20px auto; |
774 | + text-align: left; |
775 | + font-size: 0.55em; |
776 | + font-family: monospace; |
777 | + line-height: 1.2em; |
778 | + word-wrap: break-word; |
779 | + box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); } |
780 | + |
781 | +.reveal code { |
782 | + font-family: monospace; } |
783 | + |
784 | +.reveal pre code { |
785 | + display: block; |
786 | + padding: 5px; |
787 | + overflow: auto; |
788 | + max-height: 400px; |
789 | + word-wrap: normal; } |
790 | + |
791 | +.reveal table { |
792 | + margin: auto; |
793 | + border-collapse: collapse; |
794 | + border-spacing: 0; } |
795 | + |
796 | +.reveal table th { |
797 | + font-weight: bold; } |
798 | + |
799 | +.reveal table th, |
800 | +.reveal table td { |
801 | + text-align: left; |
802 | + padding: 0.2em 0.5em 0.2em 0.5em; |
803 | + border-bottom: 1px solid; } |
804 | + |
805 | +.reveal table th[align="center"], |
806 | +.reveal table td[align="center"] { |
807 | + text-align: center; } |
808 | + |
809 | +.reveal table th[align="right"], |
810 | +.reveal table td[align="right"] { |
811 | + text-align: right; } |
812 | + |
813 | +.reveal table tbody tr:last-child th, |
814 | +.reveal table tbody tr:last-child td { |
815 | + border-bottom: none; } |
816 | + |
817 | +.reveal sup { |
818 | + vertical-align: super; } |
819 | + |
820 | +.reveal sub { |
821 | + vertical-align: sub; } |
822 | + |
823 | +.reveal small { |
824 | + display: inline-block; |
825 | + font-size: 0.6em; |
826 | + line-height: 1.2em; |
827 | + vertical-align: top; } |
828 | + |
829 | +.reveal small * { |
830 | + vertical-align: top; } |
831 | + |
832 | +/********************************************* |
833 | + * LINKS |
834 | + *********************************************/ |
835 | +.reveal a { |
836 | + color: #42affa; |
837 | + text-decoration: none; |
838 | + -webkit-transition: color .15s ease; |
839 | + -moz-transition: color .15s ease; |
840 | + transition: color .15s ease; } |
841 | + |
842 | +.reveal a:hover { |
843 | + color: #8dcffc; |
844 | + text-shadow: none; |
845 | + border: none; } |
846 | + |
847 | +.reveal .roll span:after { |
848 | + color: #fff; |
849 | + background: #068de9; } |
850 | + |
851 | +/********************************************* |
852 | + * IMAGES |
853 | + *********************************************/ |
854 | +.reveal section img { |
855 | + margin: 15px 0px; |
856 | + background: rgba(255, 255, 255, 0.12); |
857 | + border: 4px solid #fff; |
858 | + box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); } |
859 | + |
860 | +.reveal section img.plain { |
861 | + border: 0; |
862 | + box-shadow: none; } |
863 | + |
864 | +.reveal a img { |
865 | + -webkit-transition: all .15s linear; |
866 | + -moz-transition: all .15s linear; |
867 | + transition: all .15s linear; } |
868 | + |
869 | +.reveal a:hover img { |
870 | + background: rgba(255, 255, 255, 0.2); |
871 | + border-color: #42affa; |
872 | + box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } |
873 | + |
874 | +/********************************************* |
875 | + * NAVIGATION CONTROLS |
876 | + *********************************************/ |
877 | +.reveal .controls .navigate-left, |
878 | +.reveal .controls .navigate-left.enabled { |
879 | + border-right-color: #42affa; } |
880 | + |
881 | +.reveal .controls .navigate-right, |
882 | +.reveal .controls .navigate-right.enabled { |
883 | + border-left-color: #42affa; } |
884 | + |
885 | +.reveal .controls .navigate-up, |
886 | +.reveal .controls .navigate-up.enabled { |
887 | + border-bottom-color: #42affa; } |
888 | + |
889 | +.reveal .controls .navigate-down, |
890 | +.reveal .controls .navigate-down.enabled { |
891 | + border-top-color: #42affa; } |
892 | + |
893 | +.reveal .controls .navigate-left.enabled:hover { |
894 | + border-right-color: #8dcffc; } |
895 | + |
896 | +.reveal .controls .navigate-right.enabled:hover { |
897 | + border-left-color: #8dcffc; } |
898 | + |
899 | +.reveal .controls .navigate-up.enabled:hover { |
900 | + border-bottom-color: #8dcffc; } |
901 | + |
902 | +.reveal .controls .navigate-down.enabled:hover { |
903 | + border-top-color: #8dcffc; } |
904 | + |
905 | +/********************************************* |
906 | + * PROGRESS BAR |
907 | + *********************************************/ |
908 | +.reveal .progress { |
909 | + background: rgba(0, 0, 0, 0.2); } |
910 | + |
911 | +.reveal .progress span { |
912 | + background: #42affa; |
913 | + -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); |
914 | + -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); |
915 | + transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } |
916 | |
917 | === added file 'openlp/core/display/html/checkerboard.png' |
918 | Binary files openlp/core/display/html/checkerboard.png 1970-01-01 00:00:00 +0000 and openlp/core/display/html/checkerboard.png 2019-02-12 20:56:20 +0000 differ |
919 | === added file 'openlp/core/display/html/display.html' |
920 | --- openlp/core/display/html/display.html 1970-01-01 00:00:00 +0000 |
921 | +++ openlp/core/display/html/display.html 2019-02-12 20:56:20 +0000 |
922 | @@ -0,0 +1,39 @@ |
923 | +<!DOCTYPE html> |
924 | +<html> |
925 | + <head> |
926 | + <title>Display Window</title> |
927 | + <link href="reveal.css" rel="stylesheet"> |
928 | + <style type="text/css"> |
929 | + body { |
930 | + background: transparent !important; |
931 | + color: #fff !important; |
932 | + } |
933 | + sup { |
934 | + vertical-align: super !important; |
935 | + font-size: smaller !important; |
936 | + } |
937 | + .reveal .slides > section, |
938 | + .reveal .slides > section > section { |
939 | + padding: 0; |
940 | + } |
941 | + .reveal > .backgrounds > .present { |
942 | + visibility: hidden !important; |
943 | + } |
944 | + #global-background { |
945 | + display: block; |
946 | + visibility: visible; |
947 | + z-index: -1; |
948 | + } |
949 | + </style> |
950 | + <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script> |
951 | + <script type="text/javascript" src="reveal.js"></script> |
952 | + <script type="text/javascript" src="display.js"></script> |
953 | + </head> |
954 | + <body> |
955 | + <div class="reveal"> |
956 | + <div id="global-background" class="slide-background present" data-loaded="true"></div> |
957 | + <div class="slides"></div> |
958 | + <div class="footer"></div> |
959 | + </div> |
960 | + </body> |
961 | +</html> |
962 | |
963 | === added file 'openlp/core/display/html/display.js' |
964 | --- openlp/core/display/html/display.js 1970-01-01 00:00:00 +0000 |
965 | +++ openlp/core/display/html/display.js 2019-02-12 20:56:20 +0000 |
966 | @@ -0,0 +1,789 @@ |
967 | +/** |
968 | + * display.js is the main Javascript file that is used to drive the display. |
969 | + */ |
970 | + |
971 | +/** |
972 | + * Background type enumeration |
973 | + */ |
974 | +var BackgroundType = { |
975 | + Transparent: "transparent", |
976 | + Solid: "solid", |
977 | + Gradient: "gradient", |
978 | + Video: "video", |
979 | + Image: "image" |
980 | +}; |
981 | + |
982 | +/** |
983 | + * Gradient type enumeration |
984 | + */ |
985 | +var GradientType = { |
986 | + Horizontal: "horizontal", |
987 | + LeftTop: "leftTop", |
988 | + LeftBottom: "leftBottom", |
989 | + Vertical: "vertical", |
990 | + Circular: "circular" |
991 | +}; |
992 | + |
993 | +/** |
994 | + * Horizontal alignment enumeration |
995 | + */ |
996 | +var HorizontalAlign = { |
997 | + Left: "left", |
998 | + Right: "right", |
999 | + Center: "center", |
1000 | + Justify: "justify" |
1001 | +}; |
1002 | + |
1003 | +/** |
1004 | + * Vertical alignment enumeration |
1005 | + */ |
1006 | +var VerticalAlign = { |
1007 | + Top: "top", |
1008 | + Middle: "middle", |
1009 | + Bottom: "bottom" |
1010 | +}; |
1011 | + |
1012 | +/** |
1013 | + * Audio state enumeration |
1014 | + */ |
1015 | +var AudioState = { |
1016 | + Playing: "playing", |
1017 | + Paused: "paused", |
1018 | + Stopped: "stopped" |
1019 | +}; |
1020 | + |
1021 | +/** |
1022 | + * Return an array of elements based on the selector query |
1023 | + * @param {string} selector - The selector to find elements |
1024 | + * @returns {array} An array of matching elements |
1025 | + */ |
1026 | +function $(selector) { |
1027 | + return Array.from(document.querySelectorAll(selector)); |
1028 | +} |
1029 | + |
1030 | +/** |
1031 | + * Build linear gradient CSS |
1032 | + * @private |
1033 | + * @param {string} startDir - Starting direction |
1034 | + * @param {string} endDir - Ending direction |
1035 | + * @param {string} startColor - The starting color |
1036 | + * @param {string} endColor - The ending color |
1037 | + * @returns {string} A string of the gradient CSS |
1038 | + */ |
1039 | +function _buildLinearGradient(startDir, endDir, startColor, endColor) { |
1040 | + return "-webkit-gradient(linear, " + startDir + ", " + endDir + ", from(" + startColor + "), to(" + endColor + ")) fixed"; |
1041 | +} |
1042 | + |
1043 | +/** |
1044 | + * Build radial gradient CSS |
1045 | + * @private |
1046 | + * @param {string} width - Width of the gradient |
1047 | + * @param {string} startColor - The starting color |
1048 | + * @param {string} endColor - The ending color |
1049 | + * @returns {string} A string of the gradient CSS |
1050 | + */ |
1051 | +function _buildRadialGradient(width, startColor, endColor) { |
1052 | + return "-webkit-gradient(radial, " + width + " 50%, 100, " + width + " 50%, " + width + ", from(" + startColor + "), to(" + endColor + ")) fixed"; |
1053 | +} |
1054 | + |
1055 | +/** |
1056 | + * Get a style value from an element (computed or manual) |
1057 | + * @private |
1058 | + * @param {Object} element - The element whose style we want |
1059 | + * @param {string} style - The name of the style we want |
1060 | + * @returns {(Number|string)} The style value (type depends on the style) |
1061 | + */ |
1062 | +function _getStyle(element, style) { |
1063 | + return document.defaultView.getComputedStyle(element).getPropertyValue(style); |
1064 | +} |
1065 | + |
1066 | +/** |
1067 | + * Convert newlines to <br> tags |
1068 | + * @private |
1069 | + * @param {string} text - The text to parse |
1070 | + * @returns {string} The text now with <br> tags |
1071 | + */ |
1072 | +function _nl2br(text) { |
1073 | + return text.replace("\r\n", "\n").replace("\n", "<br>"); |
1074 | +} |
1075 | + |
1076 | +/** |
1077 | + * Prepare text by creating paragraphs and calling _nl2br to convert newlines to <br> tags |
1078 | + * @private |
1079 | + * @param {string} text - The text to parse |
1080 | + * @returns {string} The text now with <p> and <br> tags |
1081 | + */ |
1082 | +function _prepareText(text) { |
1083 | + return "<p>" + _nl2br(text) + "</p>"; |
1084 | +} |
1085 | + |
1086 | +/** |
1087 | + * The paths we get are JSON versions of Python Path objects, so let's just fix that. |
1088 | + * @private |
1089 | + * @param {object} path - The Path object |
1090 | + * @returns {string} The actual file path |
1091 | + */ |
1092 | +function _pathToString(path) { |
1093 | + var filename = path.__Path__.join("/").replace("//", "/"); |
1094 | + if (!filename.startsWith("/")) { |
1095 | + filename = "/" + filename; |
1096 | + } |
1097 | + return filename; |
1098 | +} |
1099 | + |
1100 | +/** |
1101 | + * An audio player with a play list |
1102 | + */ |
1103 | +var AudioPlayer = function (audioElement) { |
1104 | + this._audioElement = null; |
1105 | + this._eventListeners = {}; |
1106 | + this._playlist = []; |
1107 | + this._currentTrack = null; |
1108 | + this._canRepeat = false; |
1109 | + this._state = AudioState.Stopped; |
1110 | + this.createAudioElement(); |
1111 | +}; |
1112 | + |
1113 | +/** |
1114 | + * Call all listeners associated with this event |
1115 | + * @private |
1116 | + * @param {object} event - The event that was emitted |
1117 | + */ |
1118 | +AudioPlayer.prototype._callListener = function (event) { |
1119 | + if (this._eventListeners.hasOwnProperty(event.type)) { |
1120 | + this._eventListeners[event.type].forEach(function (listener) { |
1121 | + listener(event); |
1122 | + }); |
1123 | + } |
1124 | + else { |
1125 | + console.warn("Received unknown event \"" + event.type + "\", doing nothing."); |
1126 | + } |
1127 | +}; |
1128 | + |
1129 | +/** |
1130 | + * Create the <audio> element that is used to play the audio |
1131 | + */ |
1132 | +AudioPlayer.prototype.createAudioElement = function () { |
1133 | + this._audioElement = document.createElement("audio"); |
1134 | + this._audioElement.addEventListener("ended", this.onEnded); |
1135 | + this._audioElement.addEventListener("ended", this._callListener); |
1136 | + this._audioElement.addEventListener("timeupdate", this._callListener); |
1137 | + this._audioElement.addEventListener("volumechange", this._callListener); |
1138 | + this._audioElement.addEventListener("durationchange", this._callListener); |
1139 | + this._audioElement.addEventListener("loadeddata", this._callListener); |
1140 | + document.addEventListener("complete", function(event) { |
1141 | + document.body.appendChild(this._audioElement); |
1142 | + }); |
1143 | +}; |
1144 | +AudioPlayer.prototype.addEventListener = function (eventType, listener) { |
1145 | + this._eventListeners[eventType] = this._eventListeners[eventType] || []; |
1146 | + this._eventListeners[eventType].push(listener); |
1147 | +}; |
1148 | +AudioPlayer.prototype.onEnded = function (event) { |
1149 | + this.nextTrack(); |
1150 | +}; |
1151 | +AudioPlayer.prototype.setCanRepeat = function (canRepeat) { |
1152 | + this._canRepeat = canRepeat; |
1153 | +}; |
1154 | +AudioPlayer.prototype.clearTracks = function () { |
1155 | + this._playlist = []; |
1156 | +}; |
1157 | +AudioPlayer.prototype.addTrack = function (track) { |
1158 | + this._playlist.push(track); |
1159 | +}; |
1160 | +AudioPlayer.prototype.nextTrack = function () { |
1161 | + if (!!this._currentTrack) { |
1162 | + var trackIndex = this._playlist.indexOf(this._currentTrack); |
1163 | + if ((trackIndex + 1 >= this._playlist.length) && this._canRepeat) { |
1164 | + this.play(this._playlist[0]); |
1165 | + } |
1166 | + else if (trackIndex + 1 < this._playlist.length) { |
1167 | + this.play(this._playlist[trackIndex + 1]); |
1168 | + } |
1169 | + else { |
1170 | + this.stop(); |
1171 | + } |
1172 | + } |
1173 | + else if (this._playlist.length > 0) { |
1174 | + this.play(this._playlist[0]); |
1175 | + } |
1176 | + else { |
1177 | + console.warn("No tracks in playlist, doing nothing."); |
1178 | + } |
1179 | +}; |
1180 | +AudioPlayer.prototype.play = function () { |
1181 | + if (arguments.length > 0) { |
1182 | + this._currentTrack = arguments[0]; |
1183 | + this._audioElement.src = this._currentTrack; |
1184 | + this._audioElement.play(); |
1185 | + this._state = AudioState.Playing; |
1186 | + } |
1187 | + else if (this._state == AudioState.Paused) { |
1188 | + this._audioElement.play(); |
1189 | + this._state = AudioState.Playing; |
1190 | + } |
1191 | + else { |
1192 | + console.warn("No track currently paused and no track specified, doing nothing."); |
1193 | + } |
1194 | +}; |
1195 | + |
1196 | +/** |
1197 | + * Pause |
1198 | + */ |
1199 | +AudioPlayer.prototype.pause = function () { |
1200 | + this._audioElement.pause(); |
1201 | + this._state = AudioState.Paused; |
1202 | +}; |
1203 | + |
1204 | +/** |
1205 | + * Stop playing |
1206 | + */ |
1207 | +AudioPlayer.prototype.stop = function () { |
1208 | + this._audioElement.pause(); |
1209 | + this._audioElement.src = ""; |
1210 | + this._state = AudioState.Stopped; |
1211 | +}; |
1212 | + |
1213 | +/** |
1214 | + * The Display object is what we use from OpenLP |
1215 | + */ |
1216 | +var Display = { |
1217 | + _slides: {}, |
1218 | + _revealConfig: { |
1219 | + margin: 0.0, |
1220 | + minScale: 1.0, |
1221 | + maxScale: 1.0, |
1222 | + controls: false, |
1223 | + progress: false, |
1224 | + history: false, |
1225 | + overview: false, |
1226 | + center: false, |
1227 | + help: false, |
1228 | + transition: "none", |
1229 | + backgroundTransition: "none", |
1230 | + viewDistance: 9999, |
1231 | + width: "100%", |
1232 | + height: "100%" |
1233 | + }, |
1234 | + /** |
1235 | + * Start up reveal and do any other initialisation |
1236 | + */ |
1237 | + init: function () { |
1238 | + Reveal.initialize(this._revealConfig); |
1239 | + }, |
1240 | + /** |
1241 | + * Reinitialise Reveal |
1242 | + */ |
1243 | + reinit: function () { |
1244 | + Reveal.reinitialize(); |
1245 | + }, |
1246 | + /** |
1247 | + * Set the transition type |
1248 | + * @param {string} transitionType - Can be one of "none", "fade", "slide", "convex", "concave", "zoom" |
1249 | + */ |
1250 | + setTransition: function (transitionType) { |
1251 | + Reveal.configure({"transition": transitionType}); |
1252 | + }, |
1253 | + /** |
1254 | + * Clear the current list of slides |
1255 | + */ |
1256 | + clearSlides: function () { |
1257 | + $(".slides")[0].innerHTML = ""; |
1258 | + this._slides = {}; |
1259 | + }, |
1260 | + /** |
1261 | + * Checks if the present slide content fits within the slide |
1262 | + */ |
1263 | + doesContentFit: function () { |
1264 | + console.debug("scrollHeight: " + $(".slides")[0].scrollHeight + ", clientHeight: " + $(".slides")[0].clientHeight); |
1265 | + return $(".slides")[0].clientHeight >= $(".slides")[0].scrollHeight; |
1266 | + }, |
1267 | + /** |
1268 | + * Generate the OpenLP startup splashscreen |
1269 | + * @param {string} bg_color - The background color |
1270 | + * @param {string} image - Path to the splash image |
1271 | + */ |
1272 | + setStartupSplashScreen: function(bg_color, image) { |
1273 | + Display.clearSlides(); |
1274 | + var globalBackground = $("#global-background")[0]; |
1275 | + globalBackground.style.cssText = ""; |
1276 | + globalBackground.style.setProperty("background", bg_color); |
1277 | + var slidesDiv = $(".slides")[0]; |
1278 | + var section = document.createElement("section"); |
1279 | + section.setAttribute("id", 0); |
1280 | + section.setAttribute("data-background", bg_color); |
1281 | + section.setAttribute("style", "height: 100%; width: 100%; position: relative;"); |
1282 | + var img = document.createElement('img'); |
1283 | + img.src = image; |
1284 | + img.setAttribute("style", "position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: auto;"); |
1285 | + section.appendChild(img); |
1286 | + slidesDiv.appendChild(section); |
1287 | + Display._slides['0'] = 0; |
1288 | + Display.reinit(); |
1289 | + }, |
1290 | + /** |
1291 | + * Set fullscreen image from path |
1292 | + * @param {string} bg_color - The background color |
1293 | + * @param {string} image - Path to the image |
1294 | + */ |
1295 | + setFullscreenImage: function(bg_color, image) { |
1296 | + Display.clearSlides(); |
1297 | + var globalBackground = $("#global-background")[0]; |
1298 | + globalBackground.style.cssText = ""; |
1299 | + globalBackground.style.setProperty("background", bg_color); |
1300 | + var slidesDiv = $(".slides")[0]; |
1301 | + var section = document.createElement("section"); |
1302 | + section.setAttribute("id", 0); |
1303 | + section.setAttribute("data-background", bg_color); |
1304 | + section.setAttribute("style", "height: 100%; width: 100%;"); |
1305 | + var img = document.createElement('img'); |
1306 | + img.src = image; |
1307 | + img.setAttribute("style", "height: 100%; width: 100%"); |
1308 | + section.appendChild(img); |
1309 | + slidesDiv.appendChild(section); |
1310 | + Display._slides['0'] = 0; |
1311 | + Display.reinit(); |
1312 | + }, |
1313 | + /** |
1314 | + * Set fullscreen image from base64 data |
1315 | + * @param {string} bg_color - The background color |
1316 | + * @param {string} image - Path to the image |
1317 | + */ |
1318 | + setFullscreenImageFromData: function(bg_color, image_data) { |
1319 | + Display.clearSlides(); |
1320 | + var globalBackground = $("#global-background")[0]; |
1321 | + globalBackground.style.cssText = ""; |
1322 | + globalBackground.style.setProperty("background", bg_color); |
1323 | + var slidesDiv = $(".slides")[0]; |
1324 | + var section = document.createElement("section"); |
1325 | + section.setAttribute("id", 0); |
1326 | + section.setAttribute("data-background", bg_color); |
1327 | + section.setAttribute("style", "height: 100%; width: 100%;"); |
1328 | + var img = document.createElement('img'); |
1329 | + img.src = 'data:image/png;base64,' + image_data; |
1330 | + img.setAttribute("style", "height: 100%; width: 100%"); |
1331 | + section.appendChild(img); |
1332 | + slidesDiv.appendChild(section); |
1333 | + Display._slides['0'] = 0; |
1334 | + Display.reinit(); |
1335 | + }, |
1336 | + /** |
1337 | + * Display an alert |
1338 | + * @param {string} text - The alert text |
1339 | + * @param {int} location - The location of the text (top, middle or bottom) |
1340 | + */ |
1341 | + alert: function (text, location) { |
1342 | + console.debug(" alert text: " + text, ", location: " + location); |
1343 | + /* |
1344 | + * The implementation should show an alert. |
1345 | + * It should be able to handle receiving a new alert before a previous one is "finished", basically queueing it. |
1346 | + */ |
1347 | + return; |
1348 | +}, |
1349 | + |
1350 | + /** |
1351 | + * Add a slides. If the slide exists but the HTML is different, update the slide. |
1352 | + * @param {string} verse - The verse number, e.g. "v1" |
1353 | + * @param {string} text - The HTML for the verse, e.g. "line1<br>line2" |
1354 | + * @param {string} footer_text - The HTML for the footer" |
1355 | + * @param {bool} [reinit=true] - Re-initialize Reveal. Defaults to true. |
1356 | + */ |
1357 | + addTextSlide: function (verse, text, footer_text) { |
1358 | + var html = _prepareText(text); |
1359 | + if (this._slides.hasOwnProperty(verse)) { |
1360 | + var slide = $("#" + verse)[0]; |
1361 | + if (slide.innerHTML != html) { |
1362 | + slide.innerHTML = html; |
1363 | + } |
1364 | + } |
1365 | + else { |
1366 | + var slidesDiv = $(".slides")[0]; |
1367 | + var slide = document.createElement("section"); |
1368 | + slide.setAttribute("id", verse); |
1369 | + slide.innerHTML = html; |
1370 | + slidesDiv.appendChild(slide); |
1371 | + var slides = $(".slides > section"); |
1372 | + this._slides[verse] = slides.length - 1; |
1373 | + |
1374 | + console.debug(" footer_text: " + footer_text); |
1375 | + |
1376 | + var footerDiv = $(".footer")[0]; |
1377 | + footerDiv.innerHTML = footer_text; |
1378 | + } |
1379 | + if ((arguments.length > 3) && (arguments[3] === true)) { |
1380 | + this.reinit(); |
1381 | + } |
1382 | + else if (arguments.length == 3) { |
1383 | + this.reinit(); |
1384 | + } |
1385 | + }, |
1386 | + /** |
1387 | + * Set text slides. |
1388 | + * @param {Object[]} slides - A list of slides to add as JS objects: {"verse": "v1", "text": "line 1\nline2"} |
1389 | + */ |
1390 | + setTextSlides: function (slides) { |
1391 | + Display.clearSlides(); |
1392 | + slides.forEach(function (slide) { |
1393 | + Display.addTextSlide(slide.verse, slide.text, slide.footer, false); |
1394 | + }); |
1395 | + Display.reinit(); |
1396 | + Display.goToSlide(0); |
1397 | + }, |
1398 | + /** |
1399 | + * Set image slides |
1400 | + * @param {Object[]} slides - A list of images to add as JS objects [{"path": "url/to/file"}] |
1401 | + */ |
1402 | + setImageSlides: function (slides) { |
1403 | + Display.clearSlides(); |
1404 | + var slidesDiv = $(".slides")[0]; |
1405 | + slides.forEach(function (slide, index) { |
1406 | + var section = document.createElement("section"); |
1407 | + section.setAttribute("id", index); |
1408 | + section.setAttribute("data-background", "#000"); |
1409 | + var img = document.createElement('img'); |
1410 | + img.src = slide["path"]; |
1411 | + img.setAttribute("style", "height: 100%; width: 100%;"); |
1412 | + section.appendChild(img); |
1413 | + slidesDiv.appendChild(section); |
1414 | + Display._slides[index.toString()] = index; |
1415 | + }); |
1416 | + Display.reinit(); |
1417 | + }, |
1418 | + /** |
1419 | + * Set a video |
1420 | + * @param {Object} video - The video to show as a JS object: {"path": "url/to/file"} |
1421 | + */ |
1422 | + setVideo: function (video) { |
1423 | + this.clearSlides(); |
1424 | + var section = document.createElement("section"); |
1425 | + section.setAttribute("data-background", "#000"); |
1426 | + var videoElement = document.createElement("video"); |
1427 | + videoElement.src = video["path"]; |
1428 | + videoElement.preload = "auto"; |
1429 | + videoElement.setAttribute("id", "video"); |
1430 | + videoElement.setAttribute("style", "height: 100%; width: 100%;"); |
1431 | + videoElement.autoplay = false; |
1432 | + // All the update methods below are Python functions, hence not camelCase |
1433 | + videoElement.addEventListener("durationchange", function (event) { |
1434 | + mediaWatcher.update_duration(event.target.duration); |
1435 | + }); |
1436 | + videoElement.addEventListener("timeupdate", function (event) { |
1437 | + mediaWatcher.update_progress(event.target.currentTime); |
1438 | + }); |
1439 | + videoElement.addEventListener("volumeupdate", function (event) { |
1440 | + mediaWatcher.update_volume(event.target.volume); |
1441 | + }); |
1442 | + videoElement.addEventListener("ratechange", function (event) { |
1443 | + mediaWatcher.update_playback_rate(event.target.playbackRate); |
1444 | + }); |
1445 | + videoElement.addEventListener("ended", function (event) { |
1446 | + mediaWatcher.has_ended(event.target.ended); |
1447 | + }); |
1448 | + videoElement.addEventListener("muted", function (event) { |
1449 | + mediaWatcher.has_muted(event.target.muted); |
1450 | + }); |
1451 | + section.appendChild(videoElement); |
1452 | + $(".slides")[0].appendChild(section); |
1453 | + this.reinit(); |
1454 | + }, |
1455 | + /** |
1456 | + * Play a video |
1457 | + */ |
1458 | + playVideo: function () { |
1459 | + if ($("#video").length == 1) { |
1460 | + $("#video")[0].play(); |
1461 | + } |
1462 | + }, |
1463 | + /** |
1464 | + * Pause a video |
1465 | + */ |
1466 | + pauseVideo: function () { |
1467 | + if ($("#video").length == 1) { |
1468 | + $("#video")[0].pause(); |
1469 | + } |
1470 | + }, |
1471 | + /** |
1472 | + * Stop a video |
1473 | + */ |
1474 | + stopVideo: function () { |
1475 | + if ($("#video").length == 1) { |
1476 | + $("#video")[0].pause(); |
1477 | + $("#video")[0].currentTime = 0.0; |
1478 | + } |
1479 | + }, |
1480 | + /** |
1481 | + * Go to a particular time in a video |
1482 | + * @param seconds The position in seconds to seek to |
1483 | + */ |
1484 | + seekVideo: function (seconds) { |
1485 | + if ($("#video").length == 1) { |
1486 | + $("#video")[0].currentTime = seconds; |
1487 | + } |
1488 | + }, |
1489 | + /** |
1490 | + * Set the playback rate of a video |
1491 | + * @param rate A Double of the rate. 1.0 => 100% speed, 0.75 => 75% speed, 1.25 => 125% speed, etc. |
1492 | + */ |
1493 | + setPlaybackRate: function (rate) { |
1494 | + if ($("#video").length == 1) { |
1495 | + $("#video")[0].playbackRate = rate; |
1496 | + } |
1497 | + }, |
1498 | + /** |
1499 | + * Set the volume |
1500 | + * @param level The volume level from 0 to 100. |
1501 | + */ |
1502 | + setVideoVolume: function (level) { |
1503 | + if ($("#video").length == 1) { |
1504 | + $("#video")[0].volume = level / 100.0; |
1505 | + } |
1506 | + }, |
1507 | + /** |
1508 | + * Mute the volume |
1509 | + */ |
1510 | + toggleVideoMute: function () { |
1511 | + if ($("#video").length == 1) { |
1512 | + $("#video")[0].muted = !$("#video")[0].muted; |
1513 | + } |
1514 | + }, |
1515 | + /** |
1516 | + * Clear the background audio playlist |
1517 | + */ |
1518 | + clearPlaylist: function () { |
1519 | + if ($("#background-audio").length == 1) { |
1520 | + var audio = $("#background-audio")[0]; |
1521 | + /* audio.playList */ |
1522 | + } |
1523 | + }, |
1524 | + /** |
1525 | + * Add background audio |
1526 | + * @param files The list of files as objects in an array |
1527 | + */ |
1528 | + addBackgroundAudio: function (files) { |
1529 | + }, |
1530 | + /** |
1531 | + * Go to a slide. |
1532 | + * @param slide The slide number or name, e.g. "v1", 0 |
1533 | + */ |
1534 | + goToSlide: function (slide) { |
1535 | + if (this._slides.hasOwnProperty(slide)) { |
1536 | + Reveal.slide(this._slides[slide]); |
1537 | + } |
1538 | + else { |
1539 | + Reveal.slide(slide); |
1540 | + } |
1541 | + }, |
1542 | + /** |
1543 | + * Go to the next slide in the list |
1544 | + */ |
1545 | + next: Reveal.next, |
1546 | + /** |
1547 | + * Go to the previous slide in the list |
1548 | + */ |
1549 | + prev: Reveal.prev, |
1550 | + /** |
1551 | + * Blank the screen |
1552 | + */ |
1553 | + blankToBlack: function () { |
1554 | + if (!Reveal.isPaused()) { |
1555 | + Reveal.togglePause(); |
1556 | + } |
1557 | + // var slidesDiv = $(".slides")[0]; |
1558 | + }, |
1559 | + /** |
1560 | + * Blank to theme |
1561 | + */ |
1562 | + blankToTheme: function () { |
1563 | + var slidesDiv = $(".slides")[0]; |
1564 | + slidesDiv.style.visibility = "hidden"; |
1565 | + var footerDiv = $(".footer")[0]; |
1566 | + footerDiv.style.visibility = "hidden"; |
1567 | + if (Reveal.isPaused()) { |
1568 | + Reveal.togglePause(); |
1569 | + } |
1570 | + }, |
1571 | + /** |
1572 | + * Show the screen |
1573 | + */ |
1574 | + show: function () { |
1575 | + var slidesDiv = $(".slides")[0]; |
1576 | + slidesDiv.style.visibility = "visible"; |
1577 | + var footerDiv = $(".footer")[0]; |
1578 | + footerDiv.style.visibility = "visible"; |
1579 | + if (Reveal.isPaused()) { |
1580 | + Reveal.togglePause(); |
1581 | + } |
1582 | + }, |
1583 | + /** |
1584 | + * Figure out how many lines can fit on a slide given the font size |
1585 | + * @param fontSize The font size in pts |
1586 | + */ |
1587 | + calculateLineCount: function (fontSize) { |
1588 | + var p = $(".slides > section > p"); |
1589 | + if (p.length == 0) { |
1590 | + this.addSlide("v1", "Arky arky"); |
1591 | + p = $(".slides > section > p"); |
1592 | + } |
1593 | + p = p[0]; |
1594 | + p.style.fontSize = "" + fontSize + "pt"; |
1595 | + var d = $(".slides")[0]; |
1596 | + var lh = parseFloat(_getStyle(p, "line-height")); |
1597 | + var dh = parseFloat(_getStyle(d, "height")); |
1598 | + return Math.floor(dh / lh); |
1599 | + }, |
1600 | + setTheme: function (theme) { |
1601 | + this._theme = theme; |
1602 | + var slidesDiv = $(".slides") |
1603 | + // Set the background |
1604 | + var globalBackground = $("#global-background")[0]; |
1605 | + var backgroundStyle = {}; |
1606 | + var backgroundHtml = ""; |
1607 | + switch (theme.background_type) { |
1608 | + case BackgroundType.Transparent: |
1609 | + backgroundStyle["background"] = "transparent"; |
1610 | + break; |
1611 | + case BackgroundType.Solid: |
1612 | + backgroundStyle["background"] = theme.background_color; |
1613 | + break; |
1614 | + case BackgroundType.Gradient: |
1615 | + switch (theme.background_direction) { |
1616 | + case GradientType.Horizontal: |
1617 | + backgroundStyle["background"] = _buildLinearGradient("left top", "left bottom", |
1618 | + theme.background_start_color, |
1619 | + theme.background_end_color); |
1620 | + break; |
1621 | + case GradientType.Vertical: |
1622 | + backgroundStyle["background"] = _buildLinearGradient("left top", "right top", |
1623 | + theme.background_start_color, |
1624 | + theme.background_end_color); |
1625 | + break; |
1626 | + case GradientType.LeftTop: |
1627 | + backgroundStyle["background"] = _buildLinearGradient("left top", "right bottom", |
1628 | + theme.background_start_color, |
1629 | + theme.background_end_color); |
1630 | + break; |
1631 | + case GradientType.LeftBottom: |
1632 | + backgroundStyle["background"] = _buildLinearGradient("left bottom", "right top", |
1633 | + theme.background_start_color, |
1634 | + theme.background_end_color); |
1635 | + break; |
1636 | + case GradientType.Circular: |
1637 | + backgroundStyle["background"] = _buildRadialGradient(window.innerWidth / 2, theme.background_start_color, |
1638 | + theme.background_end_color); |
1639 | + break; |
1640 | + default: |
1641 | + backgroundStyle["background"] = "#000"; |
1642 | + } |
1643 | + break; |
1644 | + case BackgroundType.Image: |
1645 | + background_filename = _pathToString(theme.background_filename); |
1646 | + backgroundStyle["background-image"] = "url('file://" + background_filename + "')"; |
1647 | + break; |
1648 | + case BackgroundType.Video: |
1649 | + background_filename = _pathToString(theme.background_filename); |
1650 | + backgroundStyle["background-color"] = theme.background_border_color; |
1651 | + backgroundHtml = "<video loop autoplay muted><source src='file://" + background_filename + "'></video>"; |
1652 | + break; |
1653 | + default: |
1654 | + backgroundStyle["background"] = "#000"; |
1655 | + } |
1656 | + globalBackground.style.cssText = ""; |
1657 | + for (var key in backgroundStyle) { |
1658 | + if (backgroundStyle.hasOwnProperty(key)) { |
1659 | + globalBackground.style.setProperty(key, backgroundStyle[key]); |
1660 | + } |
1661 | + } |
1662 | + if (!!backgroundHtml) { |
1663 | + globalBackground.innerHTML = backgroundHtml; |
1664 | + } |
1665 | + // set up the main area |
1666 | + mainStyle = { |
1667 | + "word-wrap": "break-word", |
1668 | + /*"margin": "0", |
1669 | + "padding": "0"*/ |
1670 | + }; |
1671 | + if (!!theme.font_main_outline) { |
1672 | + mainStyle["-webkit-text-stroke"] = "" + theme.font_main_outline_size + "pt " + |
1673 | + theme.font_main_outline_color; |
1674 | + mainStyle["-webkit-text-fill-color"] = theme.font_main_color; |
1675 | + } |
1676 | + mainStyle["font-family"] = theme.font_main_name; |
1677 | + mainStyle["font-size"] = "" + theme.font_main_size + "pt"; |
1678 | + mainStyle["font-style"] = !!theme.font_main_italics ? "italic" : ""; |
1679 | + mainStyle["font-weight"] = !!theme.font_main_bold ? "bold" : ""; |
1680 | + mainStyle["color"] = theme.font_main_color; |
1681 | + mainStyle["line-height"] = "" + (100 + theme.font_main_line_adjustment) + "%"; |
1682 | + mainStyle["text-align"] = theme.display_horizontal_align; |
1683 | + if (theme.display_horizontal_align != HorizontalAlign.Justify) { |
1684 | + mainStyle["white-space"] = "pre-wrap"; |
1685 | + } |
1686 | + mainStyle["vertical-align"] = theme.display_vertical_align; |
1687 | + if (theme.hasOwnProperty('font_main_shadow_size')) { |
1688 | + mainStyle["text-shadow"] = theme.font_main_shadow_color + " " + theme.font_main_shadow_size + "px " + |
1689 | + theme.font_main_shadow_size + "px"; |
1690 | + } |
1691 | + mainStyle["padding-bottom"] = theme.display_vertical_align == VerticalAlign.Bottom ? "0.5em" : "0"; |
1692 | + mainStyle["padding-left"] = !!theme.font_main_outline ? "" + (theme.font_main_outline_size * 2) + "pt" : "0"; |
1693 | + // These need to be fixed, in the Python they use a width passed in as a parameter |
1694 | + mainStyle["position"] = "absolute"; |
1695 | + mainStyle["width"] = "" + (window.innerWidth - (theme.font_main_outline_size * 4)) + "px"; |
1696 | + mainStyle["height"] = "" + (window.innerHeight - (theme.font_main_outline_size * 4)) + "px"; |
1697 | + mainStyle["left"] = "" + theme.font_main_x + "px"; |
1698 | + mainStyle["top"] = "" + theme.font_main_y + "px"; |
1699 | + var slidesDiv = $(".slides")[0]; |
1700 | + slidesDiv.style.cssText = ""; |
1701 | + for (var key in mainStyle) { |
1702 | + if (mainStyle.hasOwnProperty(key)) { |
1703 | + slidesDiv.style.setProperty(key, mainStyle[key]); |
1704 | + } |
1705 | + } |
1706 | + // Set up the footer |
1707 | + footerStyle = { |
1708 | + "text-align": "left" |
1709 | + }; |
1710 | + footerStyle["position"] = "absolute"; |
1711 | + footerStyle["left"] = "" + theme.font_footer_x + "px"; |
1712 | + footerStyle["top"] = "" + theme.font_footer_y + "px"; |
1713 | + footerStyle["bottom"] = "" + (window.innerHeight - theme.font_footer_y - theme.font_footer_height) + "px"; |
1714 | + footerStyle["width"] = "" + theme.font_footer_width + "px"; |
1715 | + footerStyle["font-family"] = theme.font_footer_name; |
1716 | + footerStyle["font-size"] = "" + theme.font_footer_size + "pt"; |
1717 | + footerStyle["color"] = theme.font_footer_color; |
1718 | + footerStyle["white-space"] = theme.font_footer_wrap ? "normal" : "nowrap"; |
1719 | + var footer = $(".footer")[0]; |
1720 | + footer.style.cssText = ""; |
1721 | + for (var key in footerStyle) { |
1722 | + if (footerStyle.hasOwnProperty(key)) { |
1723 | + footer.style.setProperty(key, footerStyle[key]); |
1724 | + } |
1725 | + } |
1726 | + }, |
1727 | + /** |
1728 | + * Return the video types supported by the video tag |
1729 | + */ |
1730 | + getVideoTypes: function () { |
1731 | + var videoElement = document.createElement('video'); |
1732 | + var videoTypes = []; |
1733 | + if (videoElement.canPlayType('video/mp4; codecs="mp4v.20.8"') == "probably" || |
1734 | + videoElement.canPlayType('video/mp4; codecs="avc1.42E01E"') == "pobably" || |
1735 | + videoElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') == "probably") { |
1736 | + videoTypes.push(['video/mp4', '*.mp4']); |
1737 | + } |
1738 | + if (videoElement.canPlayType('video/ogg; codecs="theora"') == "probably") { |
1739 | + videoTypes.push(['video/ogg', '*.ogv']); |
1740 | + } |
1741 | + if (videoElement.canPlayType('video/webm; codecs="vp8, vorbis"') == "probably") { |
1742 | + videoTypes.push(['video/webm', '*.webm']); |
1743 | + } |
1744 | + return videoTypes; |
1745 | + }, |
1746 | + /** |
1747 | + * Sets the scale of the page - used to make preview widgets scale |
1748 | + */ |
1749 | + setScale: function(scale) { |
1750 | + document.body.style.zoom = scale+"%"; |
1751 | + } |
1752 | +}; |
1753 | +new QWebChannel(qt.webChannelTransport, function (channel) { |
1754 | + window.mediaWatcher = channel.objects.mediaWatcher; |
1755 | +}); |
1756 | |
1757 | === added file 'openlp/core/display/html/openlp-splash-screen.png' |
1758 | Binary files openlp/core/display/html/openlp-splash-screen.png 1970-01-01 00:00:00 +0000 and openlp/core/display/html/openlp-splash-screen.png 2019-02-12 20:56:20 +0000 differ |
1759 | === added file 'openlp/core/display/html/reveal.css' |
1760 | --- openlp/core/display/html/reveal.css 1970-01-01 00:00:00 +0000 |
1761 | +++ openlp/core/display/html/reveal.css 2019-02-12 20:56:20 +0000 |
1762 | @@ -0,0 +1,1591 @@ |
1763 | +/*! |
1764 | + * reveal.js |
1765 | + * http://revealjs.com |
1766 | + * MIT licensed |
1767 | + * |
1768 | + * Copyright (C) 2018 Hakim El Hattab, http://hakim.se |
1769 | + */ |
1770 | +/********************************************* |
1771 | + * RESET STYLES |
1772 | + *********************************************/ |
1773 | +html, body, .reveal div, .reveal span, .reveal applet, .reveal object, .reveal iframe, |
1774 | +.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6, .reveal p, .reveal blockquote, .reveal pre, |
1775 | +.reveal a, .reveal abbr, .reveal acronym, .reveal address, .reveal big, .reveal cite, .reveal code, |
1776 | +.reveal del, .reveal dfn, .reveal em, .reveal img, .reveal ins, .reveal kbd, .reveal q, .reveal s, .reveal samp, |
1777 | +.reveal small, .reveal strike, .reveal strong, .reveal sub, .reveal sup, .reveal tt, .reveal var, |
1778 | +.reveal b, .reveal u, .reveal center, |
1779 | +.reveal dl, .reveal dt, .reveal dd, .reveal ol, .reveal ul, .reveal li, |
1780 | +.reveal fieldset, .reveal form, .reveal label, .reveal legend, |
1781 | +.reveal table, .reveal caption, .reveal tbody, .reveal tfoot, .reveal thead, .reveal tr, .reveal th, .reveal td, |
1782 | +.reveal article, .reveal aside, .reveal canvas, .reveal details, .reveal embed, |
1783 | +.reveal figure, .reveal figcaption, .reveal footer, .reveal header, .reveal hgroup, |
1784 | +.reveal menu, .reveal nav, .reveal output, .reveal ruby, .reveal section, .reveal summary, |
1785 | +.reveal time, .reveal mark, .reveal audio, .reveal video { |
1786 | + margin: 0; |
1787 | + padding: 0; |
1788 | + border: 0; |
1789 | + font-size: 100%; |
1790 | + font: inherit; |
1791 | + vertical-align: baseline; } |
1792 | + |
1793 | +.reveal article, .reveal aside, .reveal details, .reveal figcaption, .reveal figure, |
1794 | +.reveal footer, .reveal header, .reveal hgroup, .reveal menu, .reveal nav, .reveal section { |
1795 | + display: block; } |
1796 | + |
1797 | +/********************************************* |
1798 | + * GLOBAL STYLES |
1799 | + *********************************************/ |
1800 | +html, |
1801 | +body { |
1802 | + width: 100%; |
1803 | + height: 100%; |
1804 | + overflow: hidden; } |
1805 | + |
1806 | +body { |
1807 | + position: relative; |
1808 | + line-height: 1; |
1809 | + background-color: #fff; |
1810 | + color: #000; } |
1811 | + |
1812 | +/********************************************* |
1813 | + * VIEW FRAGMENTS |
1814 | + *********************************************/ |
1815 | +.reveal .slides section .fragment { |
1816 | + opacity: 0; |
1817 | + visibility: hidden; |
1818 | + transition: all .2s ease; } |
1819 | + .reveal .slides section .fragment.visible { |
1820 | + opacity: 1; |
1821 | + visibility: inherit; } |
1822 | + |
1823 | +.reveal .slides section .fragment.grow { |
1824 | + opacity: 1; |
1825 | + visibility: inherit; } |
1826 | + .reveal .slides section .fragment.grow.visible { |
1827 | + -webkit-transform: scale(1.3); |
1828 | + transform: scale(1.3); } |
1829 | + |
1830 | +.reveal .slides section .fragment.shrink { |
1831 | + opacity: 1; |
1832 | + visibility: inherit; } |
1833 | + .reveal .slides section .fragment.shrink.visible { |
1834 | + -webkit-transform: scale(0.7); |
1835 | + transform: scale(0.7); } |
1836 | + |
1837 | +.reveal .slides section .fragment.zoom-in { |
1838 | + -webkit-transform: scale(0.1); |
1839 | + transform: scale(0.1); } |
1840 | + .reveal .slides section .fragment.zoom-in.visible { |
1841 | + -webkit-transform: none; |
1842 | + transform: none; } |
1843 | + |
1844 | +.reveal .slides section .fragment.fade-out { |
1845 | + opacity: 1; |
1846 | + visibility: inherit; } |
1847 | + .reveal .slides section .fragment.fade-out.visible { |
1848 | + opacity: 0; |
1849 | + visibility: hidden; } |
1850 | + |
1851 | +.reveal .slides section .fragment.semi-fade-out { |
1852 | + opacity: 1; |
1853 | + visibility: inherit; } |
1854 | + .reveal .slides section .fragment.semi-fade-out.visible { |
1855 | + opacity: 0.5; |
1856 | + visibility: inherit; } |
1857 | + |
1858 | +.reveal .slides section .fragment.strike { |
1859 | + opacity: 1; |
1860 | + visibility: inherit; } |
1861 | + .reveal .slides section .fragment.strike.visible { |
1862 | + text-decoration: line-through; } |
1863 | + |
1864 | +.reveal .slides section .fragment.fade-up { |
1865 | + -webkit-transform: translate(0, 20%); |
1866 | + transform: translate(0, 20%); } |
1867 | + .reveal .slides section .fragment.fade-up.visible { |
1868 | + -webkit-transform: translate(0, 0); |
1869 | + transform: translate(0, 0); } |
1870 | + |
1871 | +.reveal .slides section .fragment.fade-down { |
1872 | + -webkit-transform: translate(0, -20%); |
1873 | + transform: translate(0, -20%); } |
1874 | + .reveal .slides section .fragment.fade-down.visible { |
1875 | + -webkit-transform: translate(0, 0); |
1876 | + transform: translate(0, 0); } |
1877 | + |
1878 | +.reveal .slides section .fragment.fade-right { |
1879 | + -webkit-transform: translate(-20%, 0); |
1880 | + transform: translate(-20%, 0); } |
1881 | + .reveal .slides section .fragment.fade-right.visible { |
1882 | + -webkit-transform: translate(0, 0); |
1883 | + transform: translate(0, 0); } |
1884 | + |
1885 | +.reveal .slides section .fragment.fade-left { |
1886 | + -webkit-transform: translate(20%, 0); |
1887 | + transform: translate(20%, 0); } |
1888 | + .reveal .slides section .fragment.fade-left.visible { |
1889 | + -webkit-transform: translate(0, 0); |
1890 | + transform: translate(0, 0); } |
1891 | + |
1892 | +.reveal .slides section .fragment.fade-in-then-out, |
1893 | +.reveal .slides section .fragment.current-visible { |
1894 | + opacity: 0; |
1895 | + visibility: hidden; } |
1896 | + .reveal .slides section .fragment.fade-in-then-out.current-fragment, |
1897 | + .reveal .slides section .fragment.current-visible.current-fragment { |
1898 | + opacity: 1; |
1899 | + visibility: inherit; } |
1900 | + |
1901 | +.reveal .slides section .fragment.fade-in-then-semi-out { |
1902 | + opacity: 0; |
1903 | + visibility: hidden; } |
1904 | + .reveal .slides section .fragment.fade-in-then-semi-out.visible { |
1905 | + opacity: 0.5; |
1906 | + visibility: inherit; } |
1907 | + .reveal .slides section .fragment.fade-in-then-semi-out.current-fragment { |
1908 | + opacity: 1; |
1909 | + visibility: inherit; } |
1910 | + |
1911 | +.reveal .slides section .fragment.highlight-red, |
1912 | +.reveal .slides section .fragment.highlight-current-red, |
1913 | +.reveal .slides section .fragment.highlight-green, |
1914 | +.reveal .slides section .fragment.highlight-current-green, |
1915 | +.reveal .slides section .fragment.highlight-blue, |
1916 | +.reveal .slides section .fragment.highlight-current-blue { |
1917 | + opacity: 1; |
1918 | + visibility: inherit; } |
1919 | + |
1920 | +.reveal .slides section .fragment.highlight-red.visible { |
1921 | + color: #ff2c2d; } |
1922 | + |
1923 | +.reveal .slides section .fragment.highlight-green.visible { |
1924 | + color: #17ff2e; } |
1925 | + |
1926 | +.reveal .slides section .fragment.highlight-blue.visible { |
1927 | + color: #1b91ff; } |
1928 | + |
1929 | +.reveal .slides section .fragment.highlight-current-red.current-fragment { |
1930 | + color: #ff2c2d; } |
1931 | + |
1932 | +.reveal .slides section .fragment.highlight-current-green.current-fragment { |
1933 | + color: #17ff2e; } |
1934 | + |
1935 | +.reveal .slides section .fragment.highlight-current-blue.current-fragment { |
1936 | + color: #1b91ff; } |
1937 | + |
1938 | +/********************************************* |
1939 | + * DEFAULT ELEMENT STYLES |
1940 | + *********************************************/ |
1941 | +/* Fixes issue in Chrome where italic fonts did not appear when printing to PDF */ |
1942 | +.reveal:after { |
1943 | + content: ''; |
1944 | + font-style: italic; } |
1945 | + |
1946 | +.reveal iframe { |
1947 | + z-index: 1; } |
1948 | + |
1949 | +/** Prevents layering issues in certain browser/transition combinations */ |
1950 | +.reveal a { |
1951 | + position: relative; } |
1952 | + |
1953 | +.reveal .stretch { |
1954 | + max-width: none; |
1955 | + max-height: none; } |
1956 | + |
1957 | +.reveal pre.stretch code { |
1958 | + height: 100%; |
1959 | + max-height: 100%; |
1960 | + box-sizing: border-box; } |
1961 | + |
1962 | +/********************************************* |
1963 | + * CONTROLS |
1964 | + *********************************************/ |
1965 | +@-webkit-keyframes bounce-right { |
1966 | + 0%, 10%, 25%, 40%, 50% { |
1967 | + -webkit-transform: translateX(0); |
1968 | + transform: translateX(0); } |
1969 | + 20% { |
1970 | + -webkit-transform: translateX(10px); |
1971 | + transform: translateX(10px); } |
1972 | + 30% { |
1973 | + -webkit-transform: translateX(-5px); |
1974 | + transform: translateX(-5px); } } |
1975 | +@keyframes bounce-right { |
1976 | + 0%, 10%, 25%, 40%, 50% { |
1977 | + -webkit-transform: translateX(0); |
1978 | + transform: translateX(0); } |
1979 | + 20% { |
1980 | + -webkit-transform: translateX(10px); |
1981 | + transform: translateX(10px); } |
1982 | + 30% { |
1983 | + -webkit-transform: translateX(-5px); |
1984 | + transform: translateX(-5px); } } |
1985 | + |
1986 | +@-webkit-keyframes bounce-down { |
1987 | + 0%, 10%, 25%, 40%, 50% { |
1988 | + -webkit-transform: translateY(0); |
1989 | + transform: translateY(0); } |
1990 | + 20% { |
1991 | + -webkit-transform: translateY(10px); |
1992 | + transform: translateY(10px); } |
1993 | + 30% { |
1994 | + -webkit-transform: translateY(-5px); |
1995 | + transform: translateY(-5px); } } |
1996 | + |
1997 | +@keyframes bounce-down { |
1998 | + 0%, 10%, 25%, 40%, 50% { |
1999 | + -webkit-transform: translateY(0); |
2000 | + transform: translateY(0); } |
2001 | + 20% { |
2002 | + -webkit-transform: translateY(10px); |
2003 | + transform: translateY(10px); } |
2004 | + 30% { |
2005 | + -webkit-transform: translateY(-5px); |
2006 | + transform: translateY(-5px); } } |
2007 | + |
2008 | +.reveal .controls { |
2009 | + display: none; |
2010 | + position: absolute; |
2011 | + top: auto; |
2012 | + bottom: 12px; |
2013 | + right: 12px; |
2014 | + left: auto; |
2015 | + z-index: 1; |
2016 | + color: #000; |
2017 | + pointer-events: none; |
2018 | + font-size: 10px; } |
2019 | + .reveal .controls button { |
2020 | + position: absolute; |
2021 | + padding: 0; |
2022 | + background-color: transparent; |
2023 | + border: 0; |
2024 | + outline: 0; |
2025 | + cursor: pointer; |
2026 | + color: currentColor; |
2027 | + -webkit-transform: scale(0.9999); |
2028 | + transform: scale(0.9999); |
2029 | + transition: color 0.2s ease, opacity 0.2s ease, -webkit-transform 0.2s ease; |
2030 | + transition: color 0.2s ease, opacity 0.2s ease, transform 0.2s ease; |
2031 | + z-index: 2; |
2032 | + pointer-events: auto; |
2033 | + font-size: inherit; |
2034 | + visibility: hidden; |
2035 | + opacity: 0; |
2036 | + -webkit-appearance: none; |
2037 | + -webkit-tap-highlight-color: transparent; } |
2038 | + .reveal .controls .controls-arrow:before, |
2039 | + .reveal .controls .controls-arrow:after { |
2040 | + content: ''; |
2041 | + position: absolute; |
2042 | + top: 0; |
2043 | + left: 0; |
2044 | + width: 2.6em; |
2045 | + height: 0.5em; |
2046 | + border-radius: 0.25em; |
2047 | + background-color: currentColor; |
2048 | + transition: all 0.15s ease, background-color 0.8s ease; |
2049 | + -webkit-transform-origin: 0.2em 50%; |
2050 | + transform-origin: 0.2em 50%; |
2051 | + will-change: transform; } |
2052 | + .reveal .controls .controls-arrow { |
2053 | + position: relative; |
2054 | + width: 3.6em; |
2055 | + height: 3.6em; } |
2056 | + .reveal .controls .controls-arrow:before { |
2057 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(45deg); |
2058 | + transform: translateX(0.5em) translateY(1.55em) rotate(45deg); } |
2059 | + .reveal .controls .controls-arrow:after { |
2060 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(-45deg); |
2061 | + transform: translateX(0.5em) translateY(1.55em) rotate(-45deg); } |
2062 | + .reveal .controls .controls-arrow:hover:before { |
2063 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(40deg); |
2064 | + transform: translateX(0.5em) translateY(1.55em) rotate(40deg); } |
2065 | + .reveal .controls .controls-arrow:hover:after { |
2066 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(-40deg); |
2067 | + transform: translateX(0.5em) translateY(1.55em) rotate(-40deg); } |
2068 | + .reveal .controls .controls-arrow:active:before { |
2069 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(36deg); |
2070 | + transform: translateX(0.5em) translateY(1.55em) rotate(36deg); } |
2071 | + .reveal .controls .controls-arrow:active:after { |
2072 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(-36deg); |
2073 | + transform: translateX(0.5em) translateY(1.55em) rotate(-36deg); } |
2074 | + .reveal .controls .navigate-left { |
2075 | + right: 6.4em; |
2076 | + bottom: 3.2em; |
2077 | + -webkit-transform: translateX(-10px); |
2078 | + transform: translateX(-10px); } |
2079 | + .reveal .controls .navigate-right { |
2080 | + right: 0; |
2081 | + bottom: 3.2em; |
2082 | + -webkit-transform: translateX(10px); |
2083 | + transform: translateX(10px); } |
2084 | + .reveal .controls .navigate-right .controls-arrow { |
2085 | + -webkit-transform: rotate(180deg); |
2086 | + transform: rotate(180deg); } |
2087 | + .reveal .controls .navigate-right.highlight { |
2088 | + -webkit-animation: bounce-right 2s 50 both ease-out; |
2089 | + animation: bounce-right 2s 50 both ease-out; } |
2090 | + .reveal .controls .navigate-up { |
2091 | + right: 3.2em; |
2092 | + bottom: 6.4em; |
2093 | + -webkit-transform: translateY(-10px); |
2094 | + transform: translateY(-10px); } |
2095 | + .reveal .controls .navigate-up .controls-arrow { |
2096 | + -webkit-transform: rotate(90deg); |
2097 | + transform: rotate(90deg); } |
2098 | + .reveal .controls .navigate-down { |
2099 | + right: 3.2em; |
2100 | + bottom: 0; |
2101 | + -webkit-transform: translateY(10px); |
2102 | + transform: translateY(10px); } |
2103 | + .reveal .controls .navigate-down .controls-arrow { |
2104 | + -webkit-transform: rotate(-90deg); |
2105 | + transform: rotate(-90deg); } |
2106 | + .reveal .controls .navigate-down.highlight { |
2107 | + -webkit-animation: bounce-down 2s 50 both ease-out; |
2108 | + animation: bounce-down 2s 50 both ease-out; } |
2109 | + .reveal .controls[data-controls-back-arrows="faded"] .navigate-left.enabled, |
2110 | + .reveal .controls[data-controls-back-arrows="faded"] .navigate-up.enabled { |
2111 | + opacity: 0.3; } |
2112 | + .reveal .controls[data-controls-back-arrows="faded"] .navigate-left.enabled:hover, |
2113 | + .reveal .controls[data-controls-back-arrows="faded"] .navigate-up.enabled:hover { |
2114 | + opacity: 1; } |
2115 | + .reveal .controls[data-controls-back-arrows="hidden"] .navigate-left.enabled, |
2116 | + .reveal .controls[data-controls-back-arrows="hidden"] .navigate-up.enabled { |
2117 | + opacity: 0; |
2118 | + visibility: hidden; } |
2119 | + .reveal .controls .enabled { |
2120 | + visibility: visible; |
2121 | + opacity: 0.9; |
2122 | + cursor: pointer; |
2123 | + -webkit-transform: none; |
2124 | + transform: none; } |
2125 | + .reveal .controls .enabled.fragmented { |
2126 | + opacity: 0.5; } |
2127 | + .reveal .controls .enabled:hover, |
2128 | + .reveal .controls .enabled.fragmented:hover { |
2129 | + opacity: 1; } |
2130 | + |
2131 | +.reveal:not(.has-vertical-slides) .controls .navigate-left { |
2132 | + bottom: 1.4em; |
2133 | + right: 5.5em; } |
2134 | + |
2135 | +.reveal:not(.has-vertical-slides) .controls .navigate-right { |
2136 | + bottom: 1.4em; |
2137 | + right: 0.5em; } |
2138 | + |
2139 | +.reveal:not(.has-horizontal-slides) .controls .navigate-up { |
2140 | + right: 1.4em; |
2141 | + bottom: 5em; } |
2142 | + |
2143 | +.reveal:not(.has-horizontal-slides) .controls .navigate-down { |
2144 | + right: 1.4em; |
2145 | + bottom: 0.5em; } |
2146 | + |
2147 | +.reveal.has-dark-background .controls { |
2148 | + color: #fff; } |
2149 | + |
2150 | +.reveal.has-light-background .controls { |
2151 | + color: #000; } |
2152 | + |
2153 | +.reveal.no-hover .controls .controls-arrow:hover:before, |
2154 | +.reveal.no-hover .controls .controls-arrow:active:before { |
2155 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(45deg); |
2156 | + transform: translateX(0.5em) translateY(1.55em) rotate(45deg); } |
2157 | + |
2158 | +.reveal.no-hover .controls .controls-arrow:hover:after, |
2159 | +.reveal.no-hover .controls .controls-arrow:active:after { |
2160 | + -webkit-transform: translateX(0.5em) translateY(1.55em) rotate(-45deg); |
2161 | + transform: translateX(0.5em) translateY(1.55em) rotate(-45deg); } |
2162 | + |
2163 | +@media screen and (min-width: 500px) { |
2164 | + .reveal .controls[data-controls-layout="edges"] { |
2165 | + top: 0; |
2166 | + right: 0; |
2167 | + bottom: 0; |
2168 | + left: 0; } |
2169 | + .reveal .controls[data-controls-layout="edges"] .navigate-left, |
2170 | + .reveal .controls[data-controls-layout="edges"] .navigate-right, |
2171 | + .reveal .controls[data-controls-layout="edges"] .navigate-up, |
2172 | + .reveal .controls[data-controls-layout="edges"] .navigate-down { |
2173 | + bottom: auto; |
2174 | + right: auto; } |
2175 | + .reveal .controls[data-controls-layout="edges"] .navigate-left { |
2176 | + top: 50%; |
2177 | + left: 8px; |
2178 | + margin-top: -1.8em; } |
2179 | + .reveal .controls[data-controls-layout="edges"] .navigate-right { |
2180 | + top: 50%; |
2181 | + right: 8px; |
2182 | + margin-top: -1.8em; } |
2183 | + .reveal .controls[data-controls-layout="edges"] .navigate-up { |
2184 | + top: 8px; |
2185 | + left: 50%; |
2186 | + margin-left: -1.8em; } |
2187 | + .reveal .controls[data-controls-layout="edges"] .navigate-down { |
2188 | + bottom: 8px; |
2189 | + left: 50%; |
2190 | + margin-left: -1.8em; } } |
2191 | + |
2192 | +/********************************************* |
2193 | + * PROGRESS BAR |
2194 | + *********************************************/ |
2195 | +.reveal .progress { |
2196 | + position: absolute; |
2197 | + display: none; |
2198 | + height: 3px; |
2199 | + width: 100%; |
2200 | + bottom: 0; |
2201 | + left: 0; |
2202 | + z-index: 10; |
2203 | + background-color: rgba(0, 0, 0, 0.2); |
2204 | + color: #fff; } |
2205 | + |
2206 | +.reveal .progress:after { |
2207 | + content: ''; |
2208 | + display: block; |
2209 | + position: absolute; |
2210 | + height: 10px; |
2211 | + width: 100%; |
2212 | + top: -10px; } |
2213 | + |
2214 | +.reveal .progress span { |
2215 | + display: block; |
2216 | + height: 100%; |
2217 | + width: 0px; |
2218 | + background-color: currentColor; |
2219 | + transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } |
2220 | + |
2221 | +/********************************************* |
2222 | + * SLIDE NUMBER |
2223 | + *********************************************/ |
2224 | +.reveal .slide-number { |
2225 | + position: absolute; |
2226 | + display: block; |
2227 | + right: 8px; |
2228 | + bottom: 8px; |
2229 | + z-index: 31; |
2230 | + font-family: Helvetica, sans-serif; |
2231 | + font-size: 12px; |
2232 | + line-height: 1; |
2233 | + color: #fff; |
2234 | + background-color: rgba(0, 0, 0, 0.4); |
2235 | + padding: 5px; } |
2236 | + |
2237 | +.reveal .slide-number a { |
2238 | + color: currentColor; } |
2239 | + |
2240 | +.reveal .slide-number-delimiter { |
2241 | + margin: 0 3px; } |
2242 | + |
2243 | +/********************************************* |
2244 | + * SLIDES |
2245 | + *********************************************/ |
2246 | +.reveal { |
2247 | + position: relative; |
2248 | + width: 100%; |
2249 | + height: 100%; |
2250 | + overflow: hidden; |
2251 | + -ms-touch-action: none; |
2252 | + touch-action: none; } |
2253 | + |
2254 | +@media only screen and (orientation: landscape) { |
2255 | + .reveal.ua-iphone { |
2256 | + position: fixed; } } |
2257 | + |
2258 | +.reveal .slides { |
2259 | + position: absolute; |
2260 | + width: 100%; |
2261 | + height: 100%; |
2262 | + top: 0; |
2263 | + right: 0; |
2264 | + bottom: 0; |
2265 | + left: 0; |
2266 | + margin: auto; |
2267 | + pointer-events: none; |
2268 | + overflow: visible; |
2269 | + z-index: 1; |
2270 | + text-align: center; |
2271 | + -webkit-perspective: 600px; |
2272 | + perspective: 600px; |
2273 | + -webkit-perspective-origin: 50% 40%; |
2274 | + perspective-origin: 50% 40%; } |
2275 | + |
2276 | +.reveal .slides > section { |
2277 | + -ms-perspective: 600px; } |
2278 | + |
2279 | +.reveal .slides > section, |
2280 | +.reveal .slides > section > section { |
2281 | + display: none; |
2282 | + position: absolute; |
2283 | + width: 100%; |
2284 | + padding: 20px 0px; |
2285 | + pointer-events: auto; |
2286 | + z-index: 10; |
2287 | + -webkit-transform-style: flat; |
2288 | + transform-style: flat; |
2289 | + transition: -webkit-transform-origin 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), -webkit-transform 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), visibility 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), opacity 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); |
2290 | + transition: transform-origin 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), transform 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), visibility 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985), opacity 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } |
2291 | + |
2292 | +/* Global transition speed settings */ |
2293 | +.reveal[data-transition-speed="fast"] .slides section { |
2294 | + transition-duration: 400ms; } |
2295 | + |
2296 | +.reveal[data-transition-speed="slow"] .slides section { |
2297 | + transition-duration: 1200ms; } |
2298 | + |
2299 | +/* Slide-specific transition speed overrides */ |
2300 | +.reveal .slides section[data-transition-speed="fast"] { |
2301 | + transition-duration: 400ms; } |
2302 | + |
2303 | +.reveal .slides section[data-transition-speed="slow"] { |
2304 | + transition-duration: 1200ms; } |
2305 | + |
2306 | +.reveal .slides > section.stack { |
2307 | + padding-top: 0; |
2308 | + padding-bottom: 0; |
2309 | + pointer-events: none; } |
2310 | + |
2311 | +.reveal .slides > section.present, |
2312 | +.reveal .slides > section > section.present { |
2313 | + display: block; |
2314 | + z-index: 11; |
2315 | + opacity: 1; } |
2316 | + |
2317 | +.reveal .slides > section:empty, |
2318 | +.reveal .slides > section > section:empty, |
2319 | +.reveal .slides > section[data-background-interactive], |
2320 | +.reveal .slides > section > section[data-background-interactive] { |
2321 | + pointer-events: none; } |
2322 | + |
2323 | +.reveal.center, |
2324 | +.reveal.center .slides, |
2325 | +.reveal.center .slides section { |
2326 | + min-height: 0 !important; } |
2327 | + |
2328 | +/* Don't allow interaction with invisible slides */ |
2329 | +.reveal .slides > section.future, |
2330 | +.reveal .slides > section > section.future, |
2331 | +.reveal .slides > section.past, |
2332 | +.reveal .slides > section > section.past { |
2333 | + pointer-events: none; } |
2334 | + |
2335 | +.reveal.overview .slides > section, |
2336 | +.reveal.overview .slides > section > section { |
2337 | + pointer-events: auto; } |
2338 | + |
2339 | +.reveal .slides > section.past, |
2340 | +.reveal .slides > section.future, |
2341 | +.reveal .slides > section > section.past, |
2342 | +.reveal .slides > section > section.future { |
2343 | + opacity: 0; } |
2344 | + |
2345 | +/********************************************* |
2346 | + * Mixins for readability of transitions |
2347 | + *********************************************/ |
2348 | +/********************************************* |
2349 | + * SLIDE TRANSITION |
2350 | + * Aliased 'linear' for backwards compatibility |
2351 | + *********************************************/ |
2352 | +.reveal.slide section { |
2353 | + -webkit-backface-visibility: hidden; |
2354 | + backface-visibility: hidden; } |
2355 | + |
2356 | +.reveal .slides > section[data-transition=slide].past, |
2357 | +.reveal .slides > section[data-transition~=slide-out].past, |
2358 | +.reveal.slide .slides > section:not([data-transition]).past { |
2359 | + -webkit-transform: translate(-150%, 0); |
2360 | + transform: translate(-150%, 0); } |
2361 | + |
2362 | +.reveal .slides > section[data-transition=slide].future, |
2363 | +.reveal .slides > section[data-transition~=slide-in].future, |
2364 | +.reveal.slide .slides > section:not([data-transition]).future { |
2365 | + -webkit-transform: translate(150%, 0); |
2366 | + transform: translate(150%, 0); } |
2367 | + |
2368 | +.reveal .slides > section > section[data-transition=slide].past, |
2369 | +.reveal .slides > section > section[data-transition~=slide-out].past, |
2370 | +.reveal.slide .slides > section > section:not([data-transition]).past { |
2371 | + -webkit-transform: translate(0, -150%); |
2372 | + transform: translate(0, -150%); } |
2373 | + |
2374 | +.reveal .slides > section > section[data-transition=slide].future, |
2375 | +.reveal .slides > section > section[data-transition~=slide-in].future, |
2376 | +.reveal.slide .slides > section > section:not([data-transition]).future { |
2377 | + -webkit-transform: translate(0, 150%); |
2378 | + transform: translate(0, 150%); } |
2379 | + |
2380 | +.reveal.linear section { |
2381 | + -webkit-backface-visibility: hidden; |
2382 | + backface-visibility: hidden; } |
2383 | + |
2384 | +.reveal .slides > section[data-transition=linear].past, |
2385 | +.reveal .slides > section[data-transition~=linear-out].past, |
2386 | +.reveal.linear .slides > section:not([data-transition]).past { |
2387 | + -webkit-transform: translate(-150%, 0); |
2388 | + transform: translate(-150%, 0); } |
2389 | + |
2390 | +.reveal .slides > section[data-transition=linear].future, |
2391 | +.reveal .slides > section[data-transition~=linear-in].future, |
2392 | +.reveal.linear .slides > section:not([data-transition]).future { |
2393 | + -webkit-transform: translate(150%, 0); |
2394 | + transform: translate(150%, 0); } |
2395 | + |
2396 | +.reveal .slides > section > section[data-transition=linear].past, |
2397 | +.reveal .slides > section > section[data-transition~=linear-out].past, |
2398 | +.reveal.linear .slides > section > section:not([data-transition]).past { |
2399 | + -webkit-transform: translate(0, -150%); |
2400 | + transform: translate(0, -150%); } |
2401 | + |
2402 | +.reveal .slides > section > section[data-transition=linear].future, |
2403 | +.reveal .slides > section > section[data-transition~=linear-in].future, |
2404 | +.reveal.linear .slides > section > section:not([data-transition]).future { |
2405 | + -webkit-transform: translate(0, 150%); |
2406 | + transform: translate(0, 150%); } |
2407 | + |
2408 | +/********************************************* |
2409 | + * CONVEX TRANSITION |
2410 | + * Aliased 'default' for backwards compatibility |
2411 | + *********************************************/ |
2412 | +.reveal .slides section[data-transition=default].stack, |
2413 | +.reveal.default .slides section.stack { |
2414 | + -webkit-transform-style: preserve-3d; |
2415 | + transform-style: preserve-3d; } |
2416 | + |
2417 | +.reveal .slides > section[data-transition=default].past, |
2418 | +.reveal .slides > section[data-transition~=default-out].past, |
2419 | +.reveal.default .slides > section:not([data-transition]).past { |
2420 | + -webkit-transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); |
2421 | + transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); } |
2422 | + |
2423 | +.reveal .slides > section[data-transition=default].future, |
2424 | +.reveal .slides > section[data-transition~=default-in].future, |
2425 | +.reveal.default .slides > section:not([data-transition]).future { |
2426 | + -webkit-transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); |
2427 | + transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); } |
2428 | + |
2429 | +.reveal .slides > section > section[data-transition=default].past, |
2430 | +.reveal .slides > section > section[data-transition~=default-out].past, |
2431 | +.reveal.default .slides > section > section:not([data-transition]).past { |
2432 | + -webkit-transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); |
2433 | + transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); } |
2434 | + |
2435 | +.reveal .slides > section > section[data-transition=default].future, |
2436 | +.reveal .slides > section > section[data-transition~=default-in].future, |
2437 | +.reveal.default .slides > section > section:not([data-transition]).future { |
2438 | + -webkit-transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); |
2439 | + transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); } |
2440 | + |
2441 | +.reveal .slides section[data-transition=convex].stack, |
2442 | +.reveal.convex .slides section.stack { |
2443 | + -webkit-transform-style: preserve-3d; |
2444 | + transform-style: preserve-3d; } |
2445 | + |
2446 | +.reveal .slides > section[data-transition=convex].past, |
2447 | +.reveal .slides > section[data-transition~=convex-out].past, |
2448 | +.reveal.convex .slides > section:not([data-transition]).past { |
2449 | + -webkit-transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); |
2450 | + transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); } |
2451 | + |
2452 | +.reveal .slides > section[data-transition=convex].future, |
2453 | +.reveal .slides > section[data-transition~=convex-in].future, |
2454 | +.reveal.convex .slides > section:not([data-transition]).future { |
2455 | + -webkit-transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); |
2456 | + transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); } |
2457 | + |
2458 | +.reveal .slides > section > section[data-transition=convex].past, |
2459 | +.reveal .slides > section > section[data-transition~=convex-out].past, |
2460 | +.reveal.convex .slides > section > section:not([data-transition]).past { |
2461 | + -webkit-transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); |
2462 | + transform: translate3d(0, -300px, 0) rotateX(70deg) translate3d(0, -300px, 0); } |
2463 | + |
2464 | +.reveal .slides > section > section[data-transition=convex].future, |
2465 | +.reveal .slides > section > section[data-transition~=convex-in].future, |
2466 | +.reveal.convex .slides > section > section:not([data-transition]).future { |
2467 | + -webkit-transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); |
2468 | + transform: translate3d(0, 300px, 0) rotateX(-70deg) translate3d(0, 300px, 0); } |
2469 | + |
2470 | +/********************************************* |
2471 | + * CONCAVE TRANSITION |
2472 | + *********************************************/ |
2473 | +.reveal .slides section[data-transition=concave].stack, |
2474 | +.reveal.concave .slides section.stack { |
2475 | + -webkit-transform-style: preserve-3d; |
2476 | + transform-style: preserve-3d; } |
2477 | + |
2478 | +.reveal .slides > section[data-transition=concave].past, |
2479 | +.reveal .slides > section[data-transition~=concave-out].past, |
2480 | +.reveal.concave .slides > section:not([data-transition]).past { |
2481 | + -webkit-transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); |
2482 | + transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); } |
2483 | + |
2484 | +.reveal .slides > section[data-transition=concave].future, |
2485 | +.reveal .slides > section[data-transition~=concave-in].future, |
2486 | +.reveal.concave .slides > section:not([data-transition]).future { |
2487 | + -webkit-transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); |
2488 | + transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); } |
2489 | + |
2490 | +.reveal .slides > section > section[data-transition=concave].past, |
2491 | +.reveal .slides > section > section[data-transition~=concave-out].past, |
2492 | +.reveal.concave .slides > section > section:not([data-transition]).past { |
2493 | + -webkit-transform: translate3d(0, -80%, 0) rotateX(-70deg) translate3d(0, -80%, 0); |
2494 | + transform: translate3d(0, -80%, 0) rotateX(-70deg) translate3d(0, -80%, 0); } |
2495 | + |
2496 | +.reveal .slides > section > section[data-transition=concave].future, |
2497 | +.reveal .slides > section > section[data-transition~=concave-in].future, |
2498 | +.reveal.concave .slides > section > section:not([data-transition]).future { |
2499 | + -webkit-transform: translate3d(0, 80%, 0) rotateX(70deg) translate3d(0, 80%, 0); |
2500 | + transform: translate3d(0, 80%, 0) rotateX(70deg) translate3d(0, 80%, 0); } |
2501 | + |
2502 | +/********************************************* |
2503 | + * ZOOM TRANSITION |
2504 | + *********************************************/ |
2505 | +.reveal .slides section[data-transition=zoom], |
2506 | +.reveal.zoom .slides section:not([data-transition]) { |
2507 | + transition-timing-function: ease; } |
2508 | + |
2509 | +.reveal .slides > section[data-transition=zoom].past, |
2510 | +.reveal .slides > section[data-transition~=zoom-out].past, |
2511 | +.reveal.zoom .slides > section:not([data-transition]).past { |
2512 | + visibility: hidden; |
2513 | + -webkit-transform: scale(16); |
2514 | + transform: scale(16); } |
2515 | + |
2516 | +.reveal .slides > section[data-transition=zoom].future, |
2517 | +.reveal .slides > section[data-transition~=zoom-in].future, |
2518 | +.reveal.zoom .slides > section:not([data-transition]).future { |
2519 | + visibility: hidden; |
2520 | + -webkit-transform: scale(0.2); |
2521 | + transform: scale(0.2); } |
2522 | + |
2523 | +.reveal .slides > section > section[data-transition=zoom].past, |
2524 | +.reveal .slides > section > section[data-transition~=zoom-out].past, |
2525 | +.reveal.zoom .slides > section > section:not([data-transition]).past { |
2526 | + -webkit-transform: translate(0, -150%); |
2527 | + transform: translate(0, -150%); } |
2528 | + |
2529 | +.reveal .slides > section > section[data-transition=zoom].future, |
2530 | +.reveal .slides > section > section[data-transition~=zoom-in].future, |
2531 | +.reveal.zoom .slides > section > section:not([data-transition]).future { |
2532 | + -webkit-transform: translate(0, 150%); |
2533 | + transform: translate(0, 150%); } |
2534 | + |
2535 | +/********************************************* |
2536 | + * CUBE TRANSITION |
2537 | + * |
2538 | + * WARNING: |
2539 | + * this is deprecated and will be removed in a |
2540 | + * future version. |
2541 | + *********************************************/ |
2542 | +.reveal.cube .slides { |
2543 | + -webkit-perspective: 1300px; |
2544 | + perspective: 1300px; } |
2545 | + |
2546 | +.reveal.cube .slides section { |
2547 | + padding: 30px; |
2548 | + min-height: 700px; |
2549 | + -webkit-backface-visibility: hidden; |
2550 | + backface-visibility: hidden; |
2551 | + box-sizing: border-box; |
2552 | + -webkit-transform-style: preserve-3d; |
2553 | + transform-style: preserve-3d; } |
2554 | + |
2555 | +.reveal.center.cube .slides section { |
2556 | + min-height: 0; } |
2557 | + |
2558 | +.reveal.cube .slides section:not(.stack):before { |
2559 | + content: ''; |
2560 | + position: absolute; |
2561 | + display: block; |
2562 | + width: 100%; |
2563 | + height: 100%; |
2564 | + left: 0; |
2565 | + top: 0; |
2566 | + background: rgba(0, 0, 0, 0.1); |
2567 | + border-radius: 4px; |
2568 | + -webkit-transform: translateZ(-20px); |
2569 | + transform: translateZ(-20px); } |
2570 | + |
2571 | +.reveal.cube .slides section:not(.stack):after { |
2572 | + content: ''; |
2573 | + position: absolute; |
2574 | + display: block; |
2575 | + width: 90%; |
2576 | + height: 30px; |
2577 | + left: 5%; |
2578 | + bottom: 0; |
2579 | + background: none; |
2580 | + z-index: 1; |
2581 | + border-radius: 4px; |
2582 | + box-shadow: 0px 95px 25px rgba(0, 0, 0, 0.2); |
2583 | + -webkit-transform: translateZ(-90px) rotateX(65deg); |
2584 | + transform: translateZ(-90px) rotateX(65deg); } |
2585 | + |
2586 | +.reveal.cube .slides > section.stack { |
2587 | + padding: 0; |
2588 | + background: none; } |
2589 | + |
2590 | +.reveal.cube .slides > section.past { |
2591 | + -webkit-transform-origin: 100% 0%; |
2592 | + transform-origin: 100% 0%; |
2593 | + -webkit-transform: translate3d(-100%, 0, 0) rotateY(-90deg); |
2594 | + transform: translate3d(-100%, 0, 0) rotateY(-90deg); } |
2595 | + |
2596 | +.reveal.cube .slides > section.future { |
2597 | + -webkit-transform-origin: 0% 0%; |
2598 | + transform-origin: 0% 0%; |
2599 | + -webkit-transform: translate3d(100%, 0, 0) rotateY(90deg); |
2600 | + transform: translate3d(100%, 0, 0) rotateY(90deg); } |
2601 | + |
2602 | +.reveal.cube .slides > section > section.past { |
2603 | + -webkit-transform-origin: 0% 100%; |
2604 | + transform-origin: 0% 100%; |
2605 | + -webkit-transform: translate3d(0, -100%, 0) rotateX(90deg); |
2606 | + transform: translate3d(0, -100%, 0) rotateX(90deg); } |
2607 | + |
2608 | +.reveal.cube .slides > section > section.future { |
2609 | + -webkit-transform-origin: 0% 0%; |
2610 | + transform-origin: 0% 0%; |
2611 | + -webkit-transform: translate3d(0, 100%, 0) rotateX(-90deg); |
2612 | + transform: translate3d(0, 100%, 0) rotateX(-90deg); } |
2613 | + |
2614 | +/********************************************* |
2615 | + * PAGE TRANSITION |
2616 | + * |
2617 | + * WARNING: |
2618 | + * this is deprecated and will be removed in a |
2619 | + * future version. |
2620 | + *********************************************/ |
2621 | +.reveal.page .slides { |
2622 | + -webkit-perspective-origin: 0% 50%; |
2623 | + perspective-origin: 0% 50%; |
2624 | + -webkit-perspective: 3000px; |
2625 | + perspective: 3000px; } |
2626 | + |
2627 | +.reveal.page .slides section { |
2628 | + padding: 30px; |
2629 | + min-height: 700px; |
2630 | + box-sizing: border-box; |
2631 | + -webkit-transform-style: preserve-3d; |
2632 | + transform-style: preserve-3d; } |
2633 | + |
2634 | +.reveal.page .slides section.past { |
2635 | + z-index: 12; } |
2636 | + |
2637 | +.reveal.page .slides section:not(.stack):before { |
2638 | + content: ''; |
2639 | + position: absolute; |
2640 | + display: block; |
2641 | + width: 100%; |
2642 | + height: 100%; |
2643 | + left: 0; |
2644 | + top: 0; |
2645 | + background: rgba(0, 0, 0, 0.1); |
2646 | + -webkit-transform: translateZ(-20px); |
2647 | + transform: translateZ(-20px); } |
2648 | + |
2649 | +.reveal.page .slides section:not(.stack):after { |
2650 | + content: ''; |
2651 | + position: absolute; |
2652 | + display: block; |
2653 | + width: 90%; |
2654 | + height: 30px; |
2655 | + left: 5%; |
2656 | + bottom: 0; |
2657 | + background: none; |
2658 | + z-index: 1; |
2659 | + border-radius: 4px; |
2660 | + box-shadow: 0px 95px 25px rgba(0, 0, 0, 0.2); |
2661 | + -webkit-transform: translateZ(-90px) rotateX(65deg); } |
2662 | + |
2663 | +.reveal.page .slides > section.stack { |
2664 | + padding: 0; |
2665 | + background: none; } |
2666 | + |
2667 | +.reveal.page .slides > section.past { |
2668 | + -webkit-transform-origin: 0% 0%; |
2669 | + transform-origin: 0% 0%; |
2670 | + -webkit-transform: translate3d(-40%, 0, 0) rotateY(-80deg); |
2671 | + transform: translate3d(-40%, 0, 0) rotateY(-80deg); } |
2672 | + |
2673 | +.reveal.page .slides > section.future { |
2674 | + -webkit-transform-origin: 100% 0%; |
2675 | + transform-origin: 100% 0%; |
2676 | + -webkit-transform: translate3d(0, 0, 0); |
2677 | + transform: translate3d(0, 0, 0); } |
2678 | + |
2679 | +.reveal.page .slides > section > section.past { |
2680 | + -webkit-transform-origin: 0% 0%; |
2681 | + transform-origin: 0% 0%; |
2682 | + -webkit-transform: translate3d(0, -40%, 0) rotateX(80deg); |
2683 | + transform: translate3d(0, -40%, 0) rotateX(80deg); } |
2684 | + |
2685 | +.reveal.page .slides > section > section.future { |
2686 | + -webkit-transform-origin: 0% 100%; |
2687 | + transform-origin: 0% 100%; |
2688 | + -webkit-transform: translate3d(0, 0, 0); |
2689 | + transform: translate3d(0, 0, 0); } |
2690 | + |
2691 | +/********************************************* |
2692 | + * FADE TRANSITION |
2693 | + *********************************************/ |
2694 | +.reveal .slides section[data-transition=fade], |
2695 | +.reveal.fade .slides section:not([data-transition]), |
2696 | +.reveal.fade .slides > section > section:not([data-transition]) { |
2697 | + -webkit-transform: none; |
2698 | + transform: none; |
2699 | + transition: opacity 0.5s; } |
2700 | + |
2701 | +.reveal.fade.overview .slides section, |
2702 | +.reveal.fade.overview .slides > section > section { |
2703 | + transition: none; } |
2704 | + |
2705 | +/********************************************* |
2706 | + * NO TRANSITION |
2707 | + *********************************************/ |
2708 | +.reveal .slides section[data-transition=none], |
2709 | +.reveal.none .slides section:not([data-transition]) { |
2710 | + -webkit-transform: none; |
2711 | + transform: none; |
2712 | + transition: none; } |
2713 | + |
2714 | +/********************************************* |
2715 | + * PAUSED MODE |
2716 | + *********************************************/ |
2717 | +.reveal .pause-overlay { |
2718 | + position: absolute; |
2719 | + top: 0; |
2720 | + left: 0; |
2721 | + width: 100%; |
2722 | + height: 100%; |
2723 | + background: black; |
2724 | + visibility: hidden; |
2725 | + opacity: 0; |
2726 | + z-index: 100; |
2727 | + transition: all 1s ease; } |
2728 | + |
2729 | +.reveal .pause-overlay .resume-button { |
2730 | + position: absolute; |
2731 | + bottom: 20px; |
2732 | + right: 20px; |
2733 | + color: #ccc; |
2734 | + border-radius: 2px; |
2735 | + padding: 6px 14px; |
2736 | + border: 2px solid #ccc; |
2737 | + font-size: 16px; |
2738 | + background: transparent; |
2739 | + cursor: pointer; } |
2740 | + .reveal .pause-overlay .resume-button:hover { |
2741 | + color: #fff; |
2742 | + border-color: #fff; } |
2743 | + |
2744 | +.reveal.paused .pause-overlay { |
2745 | + visibility: visible; |
2746 | + opacity: 1; } |
2747 | + |
2748 | +/********************************************* |
2749 | + * FALLBACK |
2750 | + *********************************************/ |
2751 | +.no-transforms { |
2752 | + overflow-y: auto; } |
2753 | + |
2754 | +.no-transforms .reveal .slides { |
2755 | + position: relative; |
2756 | + width: 80%; |
2757 | + height: auto !important; |
2758 | + top: 0; |
2759 | + left: 50%; |
2760 | + margin: 0; |
2761 | + text-align: center; } |
2762 | + |
2763 | +.no-transforms .reveal .controls, |
2764 | +.no-transforms .reveal .progress { |
2765 | + display: none !important; } |
2766 | + |
2767 | +.no-transforms .reveal .slides section { |
2768 | + display: block !important; |
2769 | + opacity: 1 !important; |
2770 | + position: relative !important; |
2771 | + height: auto; |
2772 | + min-height: 0; |
2773 | + top: 0; |
2774 | + left: -50%; |
2775 | + margin: 70px 0; |
2776 | + -webkit-transform: none; |
2777 | + transform: none; } |
2778 | + |
2779 | +.no-transforms .reveal .slides section section { |
2780 | + left: 0; } |
2781 | + |
2782 | +.reveal .no-transition, |
2783 | +.reveal .no-transition * { |
2784 | + transition: none !important; } |
2785 | + |
2786 | +/********************************************* |
2787 | + * PER-SLIDE BACKGROUNDS |
2788 | + *********************************************/ |
2789 | +.reveal .backgrounds { |
2790 | + position: absolute; |
2791 | + width: 100%; |
2792 | + height: 100%; |
2793 | + top: 0; |
2794 | + left: 0; |
2795 | + -webkit-perspective: 600px; |
2796 | + perspective: 600px; } |
2797 | + |
2798 | +.reveal .slide-background { |
2799 | + display: none; |
2800 | + position: absolute; |
2801 | + width: 100%; |
2802 | + height: 100%; |
2803 | + opacity: 0; |
2804 | + visibility: hidden; |
2805 | + overflow: hidden; |
2806 | + background-color: transparent; |
2807 | + transition: all 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } |
2808 | + |
2809 | +.reveal .slide-background-content { |
2810 | + position: absolute; |
2811 | + width: 100%; |
2812 | + height: 100%; |
2813 | + background-position: 50% 50%; |
2814 | + background-repeat: no-repeat; |
2815 | + background-size: cover; } |
2816 | + |
2817 | +.reveal .slide-background.stack { |
2818 | + display: block; } |
2819 | + |
2820 | +.reveal .slide-background.present { |
2821 | + opacity: 1; |
2822 | + visibility: visible; |
2823 | + z-index: 2; } |
2824 | + |
2825 | +.print-pdf .reveal .slide-background { |
2826 | + opacity: 1 !important; |
2827 | + visibility: visible !important; } |
2828 | + |
2829 | +/* Video backgrounds */ |
2830 | +.reveal .slide-background video { |
2831 | + position: absolute; |
2832 | + width: 100%; |
2833 | + height: 100%; |
2834 | + max-width: none; |
2835 | + max-height: none; |
2836 | + top: 0; |
2837 | + left: 0; |
2838 | + -o-object-fit: cover; |
2839 | + object-fit: cover; } |
2840 | + |
2841 | +.reveal .slide-background[data-background-size="contain"] video { |
2842 | + -o-object-fit: contain; |
2843 | + object-fit: contain; } |
2844 | + |
2845 | +/* Immediate transition style */ |
2846 | +.reveal[data-background-transition=none] > .backgrounds .slide-background, |
2847 | +.reveal > .backgrounds .slide-background[data-background-transition=none] { |
2848 | + transition: none; } |
2849 | + |
2850 | +/* Slide */ |
2851 | +.reveal[data-background-transition=slide] > .backgrounds .slide-background, |
2852 | +.reveal > .backgrounds .slide-background[data-background-transition=slide] { |
2853 | + opacity: 1; |
2854 | + -webkit-backface-visibility: hidden; |
2855 | + backface-visibility: hidden; } |
2856 | + |
2857 | +.reveal[data-background-transition=slide] > .backgrounds .slide-background.past, |
2858 | +.reveal > .backgrounds .slide-background.past[data-background-transition=slide] { |
2859 | + -webkit-transform: translate(-100%, 0); |
2860 | + transform: translate(-100%, 0); } |
2861 | + |
2862 | +.reveal[data-background-transition=slide] > .backgrounds .slide-background.future, |
2863 | +.reveal > .backgrounds .slide-background.future[data-background-transition=slide] { |
2864 | + -webkit-transform: translate(100%, 0); |
2865 | + transform: translate(100%, 0); } |
2866 | + |
2867 | +.reveal[data-background-transition=slide] > .backgrounds .slide-background > .slide-background.past, |
2868 | +.reveal > .backgrounds .slide-background > .slide-background.past[data-background-transition=slide] { |
2869 | + -webkit-transform: translate(0, -100%); |
2870 | + transform: translate(0, -100%); } |
2871 | + |
2872 | +.reveal[data-background-transition=slide] > .backgrounds .slide-background > .slide-background.future, |
2873 | +.reveal > .backgrounds .slide-background > .slide-background.future[data-background-transition=slide] { |
2874 | + -webkit-transform: translate(0, 100%); |
2875 | + transform: translate(0, 100%); } |
2876 | + |
2877 | +/* Convex */ |
2878 | +.reveal[data-background-transition=convex] > .backgrounds .slide-background.past, |
2879 | +.reveal > .backgrounds .slide-background.past[data-background-transition=convex] { |
2880 | + opacity: 0; |
2881 | + -webkit-transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); |
2882 | + transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0); } |
2883 | + |
2884 | +.reveal[data-background-transition=convex] > .backgrounds .slide-background.future, |
2885 | +.reveal > .backgrounds .slide-background.future[data-background-transition=convex] { |
2886 | + opacity: 0; |
2887 | + -webkit-transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); |
2888 | + transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0); } |
2889 | + |
2890 | +.reveal[data-background-transition=convex] > .backgrounds .slide-background > .slide-background.past, |
2891 | +.reveal > .backgrounds .slide-background > .slide-background.past[data-background-transition=convex] { |
2892 | + opacity: 0; |
2893 | + -webkit-transform: translate3d(0, -100%, 0) rotateX(90deg) translate3d(0, -100%, 0); |
2894 | + transform: translate3d(0, -100%, 0) rotateX(90deg) translate3d(0, -100%, 0); } |
2895 | + |
2896 | +.reveal[data-background-transition=convex] > .backgrounds .slide-background > .slide-background.future, |
2897 | +.reveal > .backgrounds .slide-background > .slide-background.future[data-background-transition=convex] { |
2898 | + opacity: 0; |
2899 | + -webkit-transform: translate3d(0, 100%, 0) rotateX(-90deg) translate3d(0, 100%, 0); |
2900 | + transform: translate3d(0, 100%, 0) rotateX(-90deg) translate3d(0, 100%, 0); } |
2901 | + |
2902 | +/* Concave */ |
2903 | +.reveal[data-background-transition=concave] > .backgrounds .slide-background.past, |
2904 | +.reveal > .backgrounds .slide-background.past[data-background-transition=concave] { |
2905 | + opacity: 0; |
2906 | + -webkit-transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); |
2907 | + transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0); } |
2908 | + |
2909 | +.reveal[data-background-transition=concave] > .backgrounds .slide-background.future, |
2910 | +.reveal > .backgrounds .slide-background.future[data-background-transition=concave] { |
2911 | + opacity: 0; |
2912 | + -webkit-transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); |
2913 | + transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0); } |
2914 | + |
2915 | +.reveal[data-background-transition=concave] > .backgrounds .slide-background > .slide-background.past, |
2916 | +.reveal > .backgrounds .slide-background > .slide-background.past[data-background-transition=concave] { |
2917 | + opacity: 0; |
2918 | + -webkit-transform: translate3d(0, -100%, 0) rotateX(-90deg) translate3d(0, -100%, 0); |
2919 | + transform: translate3d(0, -100%, 0) rotateX(-90deg) translate3d(0, -100%, 0); } |
2920 | + |
2921 | +.reveal[data-background-transition=concave] > .backgrounds .slide-background > .slide-background.future, |
2922 | +.reveal > .backgrounds .slide-background > .slide-background.future[data-background-transition=concave] { |
2923 | + opacity: 0; |
2924 | + -webkit-transform: translate3d(0, 100%, 0) rotateX(90deg) translate3d(0, 100%, 0); |
2925 | + transform: translate3d(0, 100%, 0) rotateX(90deg) translate3d(0, 100%, 0); } |
2926 | + |
2927 | +/* Zoom */ |
2928 | +.reveal[data-background-transition=zoom] > .backgrounds .slide-background, |
2929 | +.reveal > .backgrounds .slide-background[data-background-transition=zoom] { |
2930 | + transition-timing-function: ease; } |
2931 | + |
2932 | +.reveal[data-background-transition=zoom] > .backgrounds .slide-background.past, |
2933 | +.reveal > .backgrounds .slide-background.past[data-background-transition=zoom] { |
2934 | + opacity: 0; |
2935 | + visibility: hidden; |
2936 | + -webkit-transform: scale(16); |
2937 | + transform: scale(16); } |
2938 | + |
2939 | +.reveal[data-background-transition=zoom] > .backgrounds .slide-background.future, |
2940 | +.reveal > .backgrounds .slide-background.future[data-background-transition=zoom] { |
2941 | + opacity: 0; |
2942 | + visibility: hidden; |
2943 | + -webkit-transform: scale(0.2); |
2944 | + transform: scale(0.2); } |
2945 | + |
2946 | +.reveal[data-background-transition=zoom] > .backgrounds .slide-background > .slide-background.past, |
2947 | +.reveal > .backgrounds .slide-background > .slide-background.past[data-background-transition=zoom] { |
2948 | + opacity: 0; |
2949 | + visibility: hidden; |
2950 | + -webkit-transform: scale(16); |
2951 | + transform: scale(16); } |
2952 | + |
2953 | +.reveal[data-background-transition=zoom] > .backgrounds .slide-background > .slide-background.future, |
2954 | +.reveal > .backgrounds .slide-background > .slide-background.future[data-background-transition=zoom] { |
2955 | + opacity: 0; |
2956 | + visibility: hidden; |
2957 | + -webkit-transform: scale(0.2); |
2958 | + transform: scale(0.2); } |
2959 | + |
2960 | +/* Global transition speed settings */ |
2961 | +.reveal[data-transition-speed="fast"] > .backgrounds .slide-background { |
2962 | + transition-duration: 400ms; } |
2963 | + |
2964 | +.reveal[data-transition-speed="slow"] > .backgrounds .slide-background { |
2965 | + transition-duration: 1200ms; } |
2966 | + |
2967 | +/********************************************* |
2968 | + * OVERVIEW |
2969 | + *********************************************/ |
2970 | +.reveal.overview { |
2971 | + -webkit-perspective-origin: 50% 50%; |
2972 | + perspective-origin: 50% 50%; |
2973 | + -webkit-perspective: 700px; |
2974 | + perspective: 700px; } |
2975 | + .reveal.overview .slides { |
2976 | + -moz-transform-style: preserve-3d; } |
2977 | + .reveal.overview .slides section { |
2978 | + height: 100%; |
2979 | + top: 0 !important; |
2980 | + opacity: 1 !important; |
2981 | + overflow: hidden; |
2982 | + visibility: visible !important; |
2983 | + cursor: pointer; |
2984 | + box-sizing: border-box; } |
2985 | + .reveal.overview .slides section:hover, |
2986 | + .reveal.overview .slides section.present { |
2987 | + outline: 10px solid rgba(150, 150, 150, 0.4); |
2988 | + outline-offset: 10px; } |
2989 | + .reveal.overview .slides section .fragment { |
2990 | + opacity: 1; |
2991 | + transition: none; } |
2992 | + .reveal.overview .slides section:after, |
2993 | + .reveal.overview .slides section:before { |
2994 | + display: none !important; } |
2995 | + .reveal.overview .slides > section.stack { |
2996 | + padding: 0; |
2997 | + top: 0 !important; |
2998 | + background: none; |
2999 | + outline: none; |
3000 | + overflow: visible; } |
3001 | + .reveal.overview .backgrounds { |
3002 | + -webkit-perspective: inherit; |
3003 | + perspective: inherit; |
3004 | + -moz-transform-style: preserve-3d; } |
3005 | + .reveal.overview .backgrounds .slide-background { |
3006 | + opacity: 1; |
3007 | + visibility: visible; |
3008 | + outline: 10px solid rgba(150, 150, 150, 0.1); |
3009 | + outline-offset: 10px; } |
3010 | + .reveal.overview .backgrounds .slide-background.stack { |
3011 | + overflow: visible; } |
3012 | + |
3013 | +.reveal.overview .slides section, |
3014 | +.reveal.overview-deactivating .slides section { |
3015 | + transition: none; } |
3016 | + |
3017 | +.reveal.overview .backgrounds .slide-background, |
3018 | +.reveal.overview-deactivating .backgrounds .slide-background { |
3019 | + transition: none; } |
3020 | + |
3021 | +/********************************************* |
3022 | + * RTL SUPPORT |
3023 | + *********************************************/ |
3024 | +.reveal.rtl .slides, |
3025 | +.reveal.rtl .slides h1, |
3026 | +.reveal.rtl .slides h2, |
3027 | +.reveal.rtl .slides h3, |
3028 | +.reveal.rtl .slides h4, |
3029 | +.reveal.rtl .slides h5, |
3030 | +.reveal.rtl .slides h6 { |
3031 | + direction: rtl; |
3032 | + font-family: sans-serif; } |
3033 | + |
3034 | +.reveal.rtl pre, |
3035 | +.reveal.rtl code { |
3036 | + direction: ltr; } |
3037 | + |
3038 | +.reveal.rtl ol, |
3039 | +.reveal.rtl ul { |
3040 | + text-align: right; } |
3041 | + |
3042 | +.reveal.rtl .progress span { |
3043 | + float: right; } |
3044 | + |
3045 | +/********************************************* |
3046 | + * PARALLAX BACKGROUND |
3047 | + *********************************************/ |
3048 | +.reveal.has-parallax-background .backgrounds { |
3049 | + transition: all 0.8s ease; } |
3050 | + |
3051 | +/* Global transition speed settings */ |
3052 | +.reveal.has-parallax-background[data-transition-speed="fast"] .backgrounds { |
3053 | + transition-duration: 400ms; } |
3054 | + |
3055 | +.reveal.has-parallax-background[data-transition-speed="slow"] .backgrounds { |
3056 | + transition-duration: 1200ms; } |
3057 | + |
3058 | +/********************************************* |
3059 | + * LINK PREVIEW OVERLAY |
3060 | + *********************************************/ |
3061 | +.reveal .overlay { |
3062 | + position: absolute; |
3063 | + top: 0; |
3064 | + left: 0; |
3065 | + width: 100%; |
3066 | + height: 100%; |
3067 | + z-index: 1000; |
3068 | + background: rgba(0, 0, 0, 0.9); |
3069 | + opacity: 0; |
3070 | + visibility: hidden; |
3071 | + transition: all 0.3s ease; } |
3072 | + |
3073 | +.reveal .overlay.visible { |
3074 | + opacity: 1; |
3075 | + visibility: visible; } |
3076 | + |
3077 | +.reveal .overlay .spinner { |
3078 | + position: absolute; |
3079 | + display: block; |
3080 | + top: 50%; |
3081 | + left: 50%; |
3082 | + width: 32px; |
3083 | + height: 32px; |
3084 | + margin: -16px 0 0 -16px; |
3085 | + z-index: 10; |
3086 | + background-image: url(data:image/gif;base64,R0lGODlhIAAgAPMAAJmZmf%2F%2F%2F6%2Bvr8nJybW1tcDAwOjo6Nvb26ioqKOjo7Ozs%2FLy8vz8%2FAAAAAAAAAAAACH%2FC05FVFNDQVBFMi4wAwEAAAAh%2FhpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh%2BQQJCgAAACwAAAAAIAAgAAAE5xDISWlhperN52JLhSSdRgwVo1ICQZRUsiwHpTJT4iowNS8vyW2icCF6k8HMMBkCEDskxTBDAZwuAkkqIfxIQyhBQBFvAQSDITM5VDW6XNE4KagNh6Bgwe60smQUB3d4Rz1ZBApnFASDd0hihh12BkE9kjAJVlycXIg7CQIFA6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YJvpJivxNaGmLHT0VnOgSYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ%2FV%2FnmOM82XiHRLYKhKP1oZmADdEAAAh%2BQQJCgAAACwAAAAAIAAgAAAE6hDISWlZpOrNp1lGNRSdRpDUolIGw5RUYhhHukqFu8DsrEyqnWThGvAmhVlteBvojpTDDBUEIFwMFBRAmBkSgOrBFZogCASwBDEY%2FCZSg7GSE0gSCjQBMVG023xWBhklAnoEdhQEfyNqMIcKjhRsjEdnezB%2BA4k8gTwJhFuiW4dokXiloUepBAp5qaKpp6%2BHo7aWW54wl7obvEe0kRuoplCGepwSx2jJvqHEmGt6whJpGpfJCHmOoNHKaHx61WiSR92E4lbFoq%2BB6QDtuetcaBPnW6%2BO7wDHpIiK9SaVK5GgV543tzjgGcghAgAh%2BQQJCgAAACwAAAAAIAAgAAAE7hDISSkxpOrN5zFHNWRdhSiVoVLHspRUMoyUakyEe8PTPCATW9A14E0UvuAKMNAZKYUZCiBMuBakSQKG8G2FzUWox2AUtAQFcBKlVQoLgQReZhQlCIJesQXI5B0CBnUMOxMCenoCfTCEWBsJColTMANldx15BGs8B5wlCZ9Po6OJkwmRpnqkqnuSrayqfKmqpLajoiW5HJq7FL1Gr2mMMcKUMIiJgIemy7xZtJsTmsM4xHiKv5KMCXqfyUCJEonXPN2rAOIAmsfB3uPoAK%2B%2BG%2Bw48edZPK%2BM6hLJpQg484enXIdQFSS1u6UhksENEQAAIfkECQoAAAAsAAAAACAAIAAABOcQyEmpGKLqzWcZRVUQnZYg1aBSh2GUVEIQ2aQOE%2BG%2BcD4ntpWkZQj1JIiZIogDFFyHI0UxQwFugMSOFIPJftfVAEoZLBbcLEFhlQiqGp1Vd140AUklUN3eCA51C1EWMzMCezCBBmkxVIVHBWd3HHl9JQOIJSdSnJ0TDKChCwUJjoWMPaGqDKannasMo6WnM562R5YluZRwur0wpgqZE7NKUm%2BFNRPIhjBJxKZteWuIBMN4zRMIVIhffcgojwCF117i4nlLnY5ztRLsnOk%2BaV%2BoJY7V7m76PdkS4trKcdg0Zc0tTcKkRAAAIfkECQoAAAAsAAAAACAAIAAABO4QyEkpKqjqzScpRaVkXZWQEximw1BSCUEIlDohrft6cpKCk5xid5MNJTaAIkekKGQkWyKHkvhKsR7ARmitkAYDYRIbUQRQjWBwJRzChi9CRlBcY1UN4g0%2FVNB0AlcvcAYHRyZPdEQFYV8ccwR5HWxEJ02YmRMLnJ1xCYp0Y5idpQuhopmmC2KgojKasUQDk5BNAwwMOh2RtRq5uQuPZKGIJQIGwAwGf6I0JXMpC8C7kXWDBINFMxS4DKMAWVWAGYsAdNqW5uaRxkSKJOZKaU3tPOBZ4DuK2LATgJhkPJMgTwKCdFjyPHEnKxFCDhEAACH5BAkKAAAALAAAAAAgACAAAATzEMhJaVKp6s2nIkolIJ2WkBShpkVRWqqQrhLSEu9MZJKK9y1ZrqYK9WiClmvoUaF8gIQSNeF1Er4MNFn4SRSDARWroAIETg1iVwuHjYB1kYc1mwruwXKC9gmsJXliGxc%2BXiUCby9ydh1sOSdMkpMTBpaXBzsfhoc5l58Gm5yToAaZhaOUqjkDgCWNHAULCwOLaTmzswadEqggQwgHuQsHIoZCHQMMQgQGubVEcxOPFAcMDAYUA85eWARmfSRQCdcMe0zeP1AAygwLlJtPNAAL19DARdPzBOWSm1brJBi45soRAWQAAkrQIykShQ9wVhHCwCQCACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiRMDjI0Fd30%2FiI2UA5GSS5UDj2l6NoqgOgN4gksEBgYFf0FDqKgHnyZ9OX8HrgYHdHpcHQULXAS2qKpENRg7eAMLC7kTBaixUYFkKAzWAAnLC7FLVxLWDBLKCwaKTULgEwbLA4hJtOkSBNqITT3xEgfLpBtzE%2FjiuL04RGEBgwWhShRgQExHBAAh%2BQQJCgAAACwAAAAAIAAgAAAE7xDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfZiCqGk5dTESJeaOAlClzsJsqwiJwiqnFrb2nS9kmIcgEsjQydLiIlHehhpejaIjzh9eomSjZR%2BipslWIRLAgMDOR2DOqKogTB9pCUJBagDBXR6XB0EBkIIsaRsGGMMAxoDBgYHTKJiUYEGDAzHC9EACcUGkIgFzgwZ0QsSBcXHiQvOwgDdEwfFs0sDzt4S6BK4xYjkDOzn0unFeBzOBijIm1Dgmg5YFQwsCMjp1oJ8LyIAACH5BAkKAAAALAAAAAAgACAAAATwEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GGl6NoiPOH16iZKNlH6KmyWFOggHhEEvAwwMA0N9GBsEC6amhnVcEwavDAazGwIDaH1ipaYLBUTCGgQDA8NdHz0FpqgTBwsLqAbWAAnIA4FWKdMLGdYGEgraigbT0OITBcg5QwPT4xLrROZL6AuQAPUS7bxLpoWidY0JtxLHKhwwMJBTHgPKdEQAACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GAULDJCRiXo1CpGXDJOUjY%2BYip9DhToJA4RBLwMLCwVDfRgbBAaqqoZ1XBMHswsHtxtFaH1iqaoGNgAIxRpbFAgfPQSqpbgGBqUD1wBXeCYp1AYZ19JJOYgH1KwA4UBvQwXUBxPqVD9L3sbp2BNk2xvvFPJd%2BMFCN6HAAIKgNggY0KtEBAAh%2BQQJCgAAACwAAAAAIAAgAAAE6BDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfYIDMaAFdTESJeaEDAIMxYFqrOUaNW4E4ObYcCXaiBVEgULe0NJaxxtYksjh2NLkZISgDgJhHthkpU4mW6blRiYmZOlh4JWkDqILwUGBnE6TYEbCgevr0N1gH4At7gHiRpFaLNrrq8HNgAJA70AWxQIH1%2BvsYMDAzZQPC9VCNkDWUhGkuE5PxJNwiUK4UfLzOlD4WvzAHaoG9nxPi5d%2BjYUqfAhhykOFwJWiAAAIfkECQoAAAAsAAAAACAAIAAABPAQyElpUqnqzaciSoVkXVUMFaFSwlpOCcMYlErAavhOMnNLNo8KsZsMZItJEIDIFSkLGQoQTNhIsFehRww2CQLKF0tYGKYSg%2BygsZIuNqJksKgbfgIGepNo2cIUB3V1B3IvNiBYNQaDSTtfhhx0CwVPI0UJe0%2Bbm4g5VgcGoqOcnjmjqDSdnhgEoamcsZuXO1aWQy8KAwOAuTYYGwi7w5h%2BKr0SJ8MFihpNbx%2B4Erq7BYBuzsdiH1jCAzoSfl0rVirNbRXlBBlLX%2BBP0XJLAPGzTkAuAOqb0WT5AH7OcdCm5B8TgRwSRKIHQtaLCwg1RAAAOwAAAAAAAAAAAA%3D%3D); |
3087 | + visibility: visible; |
3088 | + opacity: 0.6; |
3089 | + transition: all 0.3s ease; } |
3090 | + |
3091 | +.reveal .overlay header { |
3092 | + position: absolute; |
3093 | + left: 0; |
3094 | + top: 0; |
3095 | + width: 100%; |
3096 | + height: 40px; |
3097 | + z-index: 2; |
3098 | + border-bottom: 1px solid #222; } |
3099 | + |
3100 | +.reveal .overlay header a { |
3101 | + display: inline-block; |
3102 | + width: 40px; |
3103 | + height: 40px; |
3104 | + line-height: 36px; |
3105 | + padding: 0 10px; |
3106 | + float: right; |
3107 | + opacity: 0.6; |
3108 | + box-sizing: border-box; } |
3109 | + |
3110 | +.reveal .overlay header a:hover { |
3111 | + opacity: 1; } |
3112 | + |
3113 | +.reveal .overlay header a .icon { |
3114 | + display: inline-block; |
3115 | + width: 20px; |
3116 | + height: 20px; |
3117 | + background-position: 50% 50%; |
3118 | + background-size: 100%; |
3119 | + background-repeat: no-repeat; } |
3120 | + |
3121 | +.reveal .overlay header a.close .icon { |
3122 | + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABkklEQVRYR8WX4VHDMAxG6wnoJrABZQPYBCaBTWAD2g1gE5gg6OOsXuxIlr40d81dfrSJ9V4c2VLK7spHuTJ/5wpM07QXuXc5X0opX2tEJcadjHuV80li/FgxTIEK/5QBCICBD6xEhSMGHgQPgBgLiYVAB1dpSqKDawxTohFw4JSEA3clzgIBPCURwE2JucBR7rhPJJv5OpJwDX+SfDjgx1wACQeJG1aChP9K/IMmdZ8DtESV1WyP3Bt4MwM6sj4NMxMYiqUWHQu4KYA/SYkIjOsm3BXYWMKFDwU2khjCQ4ELJUJ4SmClRArOCmSXGuKma0fYD5CbzHxFpCSGAhfAVSSUGDUk2BWZaff2g6GE15BsBQ9nwmpIGDiyHQddwNTMKkbZaf9fajXQca1EX44puJZUsnY0ObGmITE3GVLCbEhQUjGVt146j6oasWN+49Vph2w1pZ5EansNZqKBm1txbU57iRRcZ86RWMDdWtBJUHBHwoQPi1GV+JCbntmvok7iTX4/Up9mgyTc/FJYDTcndgH/AA5A/CHsyEkVAAAAAElFTkSuQmCC); } |
3123 | + |
3124 | +.reveal .overlay header a.external .icon { |
3125 | + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAcElEQVRYR+2WSQoAIQwEzf8f7XiOMkUQxUPlGkM3hVmiQfQR9GYnH1SsAQlI4DiBqkCMoNb9y2e90IAEJPAcgdznU9+engMaeJ7Azh5Y1U67gAho4DqBqmB1buAf0MB1AlVBek83ZPkmJMGc1wAR+AAqod/B97TRpQAAAABJRU5ErkJggg==); } |
3126 | + |
3127 | +.reveal .overlay .viewport { |
3128 | + position: absolute; |
3129 | + display: -webkit-box; |
3130 | + display: -ms-flexbox; |
3131 | + display: flex; |
3132 | + top: 40px; |
3133 | + right: 0; |
3134 | + bottom: 0; |
3135 | + left: 0; } |
3136 | + |
3137 | +.reveal .overlay.overlay-preview .viewport iframe { |
3138 | + width: 100%; |
3139 | + height: 100%; |
3140 | + max-width: 100%; |
3141 | + max-height: 100%; |
3142 | + border: 0; |
3143 | + opacity: 0; |
3144 | + visibility: hidden; |
3145 | + transition: all 0.3s ease; } |
3146 | + |
3147 | +.reveal .overlay.overlay-preview.loaded .viewport iframe { |
3148 | + opacity: 1; |
3149 | + visibility: visible; } |
3150 | + |
3151 | +.reveal .overlay.overlay-preview.loaded .viewport-inner { |
3152 | + position: absolute; |
3153 | + z-index: -1; |
3154 | + left: 0; |
3155 | + top: 45%; |
3156 | + width: 100%; |
3157 | + text-align: center; |
3158 | + letter-spacing: normal; } |
3159 | + |
3160 | +.reveal .overlay.overlay-preview .x-frame-error { |
3161 | + opacity: 0; |
3162 | + transition: opacity 0.3s ease 0.3s; } |
3163 | + |
3164 | +.reveal .overlay.overlay-preview.loaded .x-frame-error { |
3165 | + opacity: 1; } |
3166 | + |
3167 | +.reveal .overlay.overlay-preview.loaded .spinner { |
3168 | + opacity: 0; |
3169 | + visibility: hidden; |
3170 | + -webkit-transform: scale(0.2); |
3171 | + transform: scale(0.2); } |
3172 | + |
3173 | +.reveal .overlay.overlay-help .viewport { |
3174 | + overflow: auto; |
3175 | + color: #fff; } |
3176 | + |
3177 | +.reveal .overlay.overlay-help .viewport .viewport-inner { |
3178 | + width: 600px; |
3179 | + margin: auto; |
3180 | + padding: 20px 20px 80px 20px; |
3181 | + text-align: center; |
3182 | + letter-spacing: normal; } |
3183 | + |
3184 | +.reveal .overlay.overlay-help .viewport .viewport-inner .title { |
3185 | + font-size: 20px; } |
3186 | + |
3187 | +.reveal .overlay.overlay-help .viewport .viewport-inner table { |
3188 | + border: 1px solid #fff; |
3189 | + border-collapse: collapse; |
3190 | + font-size: 16px; } |
3191 | + |
3192 | +.reveal .overlay.overlay-help .viewport .viewport-inner table th, |
3193 | +.reveal .overlay.overlay-help .viewport .viewport-inner table td { |
3194 | + width: 200px; |
3195 | + padding: 14px; |
3196 | + border: 1px solid #fff; |
3197 | + vertical-align: middle; } |
3198 | + |
3199 | +.reveal .overlay.overlay-help .viewport .viewport-inner table th { |
3200 | + padding-top: 20px; |
3201 | + padding-bottom: 20px; } |
3202 | + |
3203 | +/********************************************* |
3204 | + * PLAYBACK COMPONENT |
3205 | + *********************************************/ |
3206 | +.reveal .playback { |
3207 | + position: absolute; |
3208 | + left: 15px; |
3209 | + bottom: 20px; |
3210 | + z-index: 30; |
3211 | + cursor: pointer; |
3212 | + transition: all 400ms ease; |
3213 | + -webkit-tap-highlight-color: transparent; } |
3214 | + |
3215 | +.reveal.overview .playback { |
3216 | + opacity: 0; |
3217 | + visibility: hidden; } |
3218 | + |
3219 | +/********************************************* |
3220 | + * ROLLING LINKS |
3221 | + *********************************************/ |
3222 | +.reveal .roll { |
3223 | + display: inline-block; |
3224 | + line-height: 1.2; |
3225 | + overflow: hidden; |
3226 | + vertical-align: top; |
3227 | + -webkit-perspective: 400px; |
3228 | + perspective: 400px; |
3229 | + -webkit-perspective-origin: 50% 50%; |
3230 | + perspective-origin: 50% 50%; } |
3231 | + |
3232 | +.reveal .roll:hover { |
3233 | + background: none; |
3234 | + text-shadow: none; } |
3235 | + |
3236 | +.reveal .roll span { |
3237 | + display: block; |
3238 | + position: relative; |
3239 | + padding: 0 2px; |
3240 | + pointer-events: none; |
3241 | + transition: all 400ms ease; |
3242 | + -webkit-transform-origin: 50% 0%; |
3243 | + transform-origin: 50% 0%; |
3244 | + -webkit-transform-style: preserve-3d; |
3245 | + transform-style: preserve-3d; |
3246 | + -webkit-backface-visibility: hidden; |
3247 | + backface-visibility: hidden; } |
3248 | + |
3249 | +.reveal .roll:hover span { |
3250 | + background: rgba(0, 0, 0, 0.5); |
3251 | + -webkit-transform: translate3d(0px, 0px, -45px) rotateX(90deg); |
3252 | + transform: translate3d(0px, 0px, -45px) rotateX(90deg); } |
3253 | + |
3254 | +.reveal .roll span:after { |
3255 | + content: attr(data-title); |
3256 | + display: block; |
3257 | + position: absolute; |
3258 | + left: 0; |
3259 | + top: 0; |
3260 | + padding: 0 2px; |
3261 | + -webkit-backface-visibility: hidden; |
3262 | + backface-visibility: hidden; |
3263 | + -webkit-transform-origin: 50% 0%; |
3264 | + transform-origin: 50% 0%; |
3265 | + -webkit-transform: translate3d(0px, 110%, 0px) rotateX(-90deg); |
3266 | + transform: translate3d(0px, 110%, 0px) rotateX(-90deg); } |
3267 | + |
3268 | +/********************************************* |
3269 | + * SPEAKER NOTES |
3270 | + *********************************************/ |
3271 | +.reveal aside.notes { |
3272 | + display: none; } |
3273 | + |
3274 | +.reveal .speaker-notes { |
3275 | + display: none; |
3276 | + position: absolute; |
3277 | + width: 25vw; |
3278 | + height: 100%; |
3279 | + top: 0; |
3280 | + left: 100%; |
3281 | + padding: 14px 18px 14px 18px; |
3282 | + z-index: 1; |
3283 | + font-size: 18px; |
3284 | + line-height: 1.4; |
3285 | + border: 1px solid rgba(0, 0, 0, 0.05); |
3286 | + color: #222; |
3287 | + background-color: #f5f5f5; |
3288 | + overflow: auto; |
3289 | + box-sizing: border-box; |
3290 | + text-align: left; |
3291 | + font-family: Helvetica, sans-serif; |
3292 | + -webkit-overflow-scrolling: touch; } |
3293 | + .reveal .speaker-notes .notes-placeholder { |
3294 | + color: #ccc; |
3295 | + font-style: italic; } |
3296 | + .reveal .speaker-notes:focus { |
3297 | + outline: none; } |
3298 | + .reveal .speaker-notes:before { |
3299 | + content: 'Speaker notes'; |
3300 | + display: block; |
3301 | + margin-bottom: 10px; |
3302 | + opacity: 0.5; } |
3303 | + |
3304 | +.reveal.show-notes { |
3305 | + max-width: 75vw; |
3306 | + overflow: visible; } |
3307 | + |
3308 | +.reveal.show-notes .speaker-notes { |
3309 | + display: block; } |
3310 | + |
3311 | +@media screen and (min-width: 1600px) { |
3312 | + .reveal .speaker-notes { |
3313 | + font-size: 20px; } } |
3314 | + |
3315 | +@media screen and (max-width: 1024px) { |
3316 | + .reveal.show-notes { |
3317 | + border-left: 0; |
3318 | + max-width: none; |
3319 | + max-height: 70%; |
3320 | + overflow: visible; } |
3321 | + .reveal.show-notes .speaker-notes { |
3322 | + top: 100%; |
3323 | + left: 0; |
3324 | + width: 100%; |
3325 | + height: 42.8571428571%; } } |
3326 | + |
3327 | +@media screen and (max-width: 600px) { |
3328 | + .reveal.show-notes { |
3329 | + max-height: 60%; } |
3330 | + .reveal.show-notes .speaker-notes { |
3331 | + top: 100%; |
3332 | + height: 66.6666666667%; } |
3333 | + .reveal .speaker-notes { |
3334 | + font-size: 14px; } } |
3335 | + |
3336 | +/********************************************* |
3337 | + * ZOOM PLUGIN |
3338 | + *********************************************/ |
3339 | +.zoomed .reveal *, |
3340 | +.zoomed .reveal *:before, |
3341 | +.zoomed .reveal *:after { |
3342 | + -webkit-backface-visibility: visible !important; |
3343 | + backface-visibility: visible !important; } |
3344 | + |
3345 | +.zoomed .reveal .progress, |
3346 | +.zoomed .reveal .controls { |
3347 | + opacity: 0; } |
3348 | + |
3349 | +.zoomed .reveal .roll span { |
3350 | + background: none; } |
3351 | + |
3352 | +.zoomed .reveal .roll span:after { |
3353 | + visibility: hidden; } |
3354 | |
3355 | === added file 'openlp/core/display/html/reveal.js' |
3356 | --- openlp/core/display/html/reveal.js 1970-01-01 00:00:00 +0000 |
3357 | +++ openlp/core/display/html/reveal.js 2019-02-12 20:56:20 +0000 |
3358 | @@ -0,0 +1,5586 @@ |
3359 | +/*! |
3360 | + * reveal.js |
3361 | + * http://revealjs.com |
3362 | + * MIT licensed |
3363 | + * |
3364 | + * Copyright (C) 2018 Hakim El Hattab, http://hakim.se |
3365 | + */ |
3366 | +(function( root, factory ) { |
3367 | + if( typeof define === 'function' && define.amd ) { |
3368 | + // AMD. Register as an anonymous module. |
3369 | + define( function() { |
3370 | + root.Reveal = factory(); |
3371 | + return root.Reveal; |
3372 | + } ); |
3373 | + } else if( typeof exports === 'object' ) { |
3374 | + // Node. Does not work with strict CommonJS. |
3375 | + module.exports = factory(); |
3376 | + } else { |
3377 | + // Browser globals. |
3378 | + root.Reveal = factory(); |
3379 | + } |
3380 | +}( this, function() { |
3381 | + |
3382 | + 'use strict'; |
3383 | + |
3384 | + var Reveal; |
3385 | + |
3386 | + // The reveal.js version |
3387 | + var VERSION = '3.7.0'; |
3388 | + |
3389 | + var SLIDES_SELECTOR = '.slides section', |
3390 | + HORIZONTAL_SLIDES_SELECTOR = '.slides>section', |
3391 | + VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section', |
3392 | + HOME_SLIDE_SELECTOR = '.slides>section:first-of-type', |
3393 | + UA = navigator.userAgent, |
3394 | + |
3395 | + // Configuration defaults, can be overridden at initialization time |
3396 | + config = { |
3397 | + |
3398 | + // The "normal" size of the presentation, aspect ratio will be preserved |
3399 | + // when the presentation is scaled to fit different resolutions |
3400 | + width: 960, |
3401 | + height: 700, |
3402 | + |
3403 | + // Factor of the display size that should remain empty around the content |
3404 | + margin: 0.04, |
3405 | + |
3406 | + // Bounds for smallest/largest possible scale to apply to content |
3407 | + minScale: 0.2, |
3408 | + maxScale: 2.0, |
3409 | + |
3410 | + // Display presentation control arrows |
3411 | + controls: true, |
3412 | + |
3413 | + // Help the user learn the controls by providing hints, for example by |
3414 | + // bouncing the down arrow when they first encounter a vertical slide |
3415 | + controlsTutorial: true, |
3416 | + |
3417 | + // Determines where controls appear, "edges" or "bottom-right" |
3418 | + controlsLayout: 'bottom-right', |
3419 | + |
3420 | + // Visibility rule for backwards navigation arrows; "faded", "hidden" |
3421 | + // or "visible" |
3422 | + controlsBackArrows: 'faded', |
3423 | + |
3424 | + // Display a presentation progress bar |
3425 | + progress: true, |
3426 | + |
3427 | + // Display the page number of the current slide |
3428 | + slideNumber: false, |
3429 | + |
3430 | + // Use 1 based indexing for # links to match slide number (default is zero |
3431 | + // based) |
3432 | + hashOneBasedIndex: false, |
3433 | + |
3434 | + // Determine which displays to show the slide number on |
3435 | + showSlideNumber: 'all', |
3436 | + |
3437 | + // Push each slide change to the browser history |
3438 | + history: false, |
3439 | + |
3440 | + // Enable keyboard shortcuts for navigation |
3441 | + keyboard: true, |
3442 | + |
3443 | + // Optional function that blocks keyboard events when retuning false |
3444 | + keyboardCondition: null, |
3445 | + |
3446 | + // Enable the slide overview mode |
3447 | + overview: true, |
3448 | + |
3449 | + // Disables the default reveal.js slide layout so that you can use |
3450 | + // custom CSS layout |
3451 | + disableLayout: false, |
3452 | + |
3453 | + // Vertical centering of slides |
3454 | + center: true, |
3455 | + |
3456 | + // Enables touch navigation on devices with touch input |
3457 | + touch: true, |
3458 | + |
3459 | + // Loop the presentation |
3460 | + loop: false, |
3461 | + |
3462 | + // Change the presentation direction to be RTL |
3463 | + rtl: false, |
3464 | + |
3465 | + // Randomizes the order of slides each time the presentation loads |
3466 | + shuffle: false, |
3467 | + |
3468 | + // Turns fragments on and off globally |
3469 | + fragments: true, |
3470 | + |
3471 | + // Flags whether to include the current fragment in the URL, |
3472 | + // so that reloading brings you to the same fragment position |
3473 | + fragmentInURL: false, |
3474 | + |
3475 | + // Flags if the presentation is running in an embedded mode, |
3476 | + // i.e. contained within a limited portion of the screen |
3477 | + embedded: false, |
3478 | + |
3479 | + // Flags if we should show a help overlay when the question-mark |
3480 | + // key is pressed |
3481 | + help: true, |
3482 | + |
3483 | + // Flags if it should be possible to pause the presentation (blackout) |
3484 | + pause: true, |
3485 | + |
3486 | + // Flags if speaker notes should be visible to all viewers |
3487 | + showNotes: false, |
3488 | + |
3489 | + // Global override for autolaying embedded media (video/audio/iframe) |
3490 | + // - null: Media will only autoplay if data-autoplay is present |
3491 | + // - true: All media will autoplay, regardless of individual setting |
3492 | + // - false: No media will autoplay, regardless of individual setting |
3493 | + autoPlayMedia: null, |
3494 | + |
3495 | + // Controls automatic progression to the next slide |
3496 | + // - 0: Auto-sliding only happens if the data-autoslide HTML attribute |
3497 | + // is present on the current slide or fragment |
3498 | + // - 1+: All slides will progress automatically at the given interval |
3499 | + // - false: No auto-sliding, even if data-autoslide is present |
3500 | + autoSlide: 0, |
3501 | + |
3502 | + // Stop auto-sliding after user input |
3503 | + autoSlideStoppable: true, |
3504 | + |
3505 | + // Use this method for navigation when auto-sliding (defaults to navigateNext) |
3506 | + autoSlideMethod: null, |
3507 | + |
3508 | + // Specify the average time in seconds that you think you will spend |
3509 | + // presenting each slide. This is used to show a pacing timer in the |
3510 | + // speaker view |
3511 | + defaultTiming: null, |
3512 | + |
3513 | + // Enable slide navigation via mouse wheel |
3514 | + mouseWheel: false, |
3515 | + |
3516 | + // Apply a 3D roll to links on hover |
3517 | + rollingLinks: false, |
3518 | + |
3519 | + // Hides the address bar on mobile devices |
3520 | + hideAddressBar: true, |
3521 | + |
3522 | + // Opens links in an iframe preview overlay |
3523 | + // Add `data-preview-link` and `data-preview-link="false"` to customise each link |
3524 | + // individually |
3525 | + previewLinks: false, |
3526 | + |
3527 | + // Exposes the reveal.js API through window.postMessage |
3528 | + postMessage: true, |
3529 | + |
3530 | + // Dispatches all reveal.js events to the parent window through postMessage |
3531 | + postMessageEvents: false, |
3532 | + |
3533 | + // Focuses body when page changes visibility to ensure keyboard shortcuts work |
3534 | + focusBodyOnPageVisibilityChange: true, |
3535 | + |
3536 | + // Transition style |
3537 | + transition: 'slide', // none/fade/slide/convex/concave/zoom |
3538 | + |
3539 | + // Transition speed |
3540 | + transitionSpeed: 'default', // default/fast/slow |
3541 | + |
3542 | + // Transition style for full page slide backgrounds |
3543 | + backgroundTransition: 'fade', // none/fade/slide/convex/concave/zoom |
3544 | + |
3545 | + // Parallax background image |
3546 | + parallaxBackgroundImage: '', // CSS syntax, e.g. "a.jpg" |
3547 | + |
3548 | + // Parallax background size |
3549 | + parallaxBackgroundSize: '', // CSS syntax, e.g. "3000px 2000px" |
3550 | + |
3551 | + // Parallax background repeat |
3552 | + parallaxBackgroundRepeat: '', // repeat/repeat-x/repeat-y/no-repeat/initial/inherit |
3553 | + |
3554 | + // Parallax background position |
3555 | + parallaxBackgroundPosition: '', // CSS syntax, e.g. "top left" |
3556 | + |
3557 | + // Amount of pixels to move the parallax background per slide step |
3558 | + parallaxBackgroundHorizontal: null, |
3559 | + parallaxBackgroundVertical: null, |
3560 | + |
3561 | + // The maximum number of pages a single slide can expand onto when printing |
3562 | + // to PDF, unlimited by default |
3563 | + pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY, |
3564 | + |
3565 | + // Prints each fragment on a separate slide |
3566 | + pdfSeparateFragments: true, |
3567 | + |
3568 | + // Offset used to reduce the height of content within exported PDF pages. |
3569 | + // This exists to account for environment differences based on how you |
3570 | + // print to PDF. CLI printing options, like phantomjs and wkpdf, can end |
3571 | + // on precisely the total height of the document whereas in-browser |
3572 | + // printing has to end one pixel before. |
3573 | + pdfPageHeightOffset: -1, |
3574 | + |
3575 | + // Number of slides away from the current that are visible |
3576 | + viewDistance: 3, |
3577 | + |
3578 | + // The display mode that will be used to show slides |
3579 | + display: 'block', |
3580 | + |
3581 | + // Script dependencies to load |
3582 | + dependencies: [] |
3583 | + |
3584 | + }, |
3585 | + |
3586 | + // Flags if Reveal.initialize() has been called |
3587 | + initialized = false, |
3588 | + |
3589 | + // Flags if reveal.js is loaded (has dispatched the 'ready' event) |
3590 | + loaded = false, |
3591 | + |
3592 | + // Flags if the overview mode is currently active |
3593 | + overview = false, |
3594 | + |
3595 | + // Holds the dimensions of our overview slides, including margins |
3596 | + overviewSlideWidth = null, |
3597 | + overviewSlideHeight = null, |
3598 | + |
3599 | + // The horizontal and vertical index of the currently active slide |
3600 | + indexh, |
3601 | + indexv, |
3602 | + |
3603 | + // The previous and current slide HTML elements |
3604 | + previousSlide, |
3605 | + currentSlide, |
3606 | + |
3607 | + previousBackground, |
3608 | + |
3609 | + // Remember which directions that the user has navigated towards |
3610 | + hasNavigatedRight = false, |
3611 | + hasNavigatedDown = false, |
3612 | + |
3613 | + // Slides may hold a data-state attribute which we pick up and apply |
3614 | + // as a class to the body. This list contains the combined state of |
3615 | + // all current slides. |
3616 | + state = [], |
3617 | + |
3618 | + // The current scale of the presentation (see width/height config) |
3619 | + scale = 1, |
3620 | + |
3621 | + // CSS transform that is currently applied to the slides container, |
3622 | + // split into two groups |
3623 | + slidesTransform = { layout: '', overview: '' }, |
3624 | + |
3625 | + // Cached references to DOM elements |
3626 | + dom = {}, |
3627 | + |
3628 | + // Features supported by the browser, see #checkCapabilities() |
3629 | + features = {}, |
3630 | + |
3631 | + // Client is a mobile device, see #checkCapabilities() |
3632 | + isMobileDevice, |
3633 | + |
3634 | + // Client is a desktop Chrome, see #checkCapabilities() |
3635 | + isChrome, |
3636 | + |
3637 | + // Throttles mouse wheel navigation |
3638 | + lastMouseWheelStep = 0, |
3639 | + |
3640 | + // Delays updates to the URL due to a Chrome thumbnailer bug |
3641 | + writeURLTimeout = 0, |
3642 | + |
3643 | + // Flags if the interaction event listeners are bound |
3644 | + eventsAreBound = false, |
3645 | + |
3646 | + // The current auto-slide duration |
3647 | + autoSlide = 0, |
3648 | + |
3649 | + // Auto slide properties |
3650 | + autoSlidePlayer, |
3651 | + autoSlideTimeout = 0, |
3652 | + autoSlideStartTime = -1, |
3653 | + autoSlidePaused = false, |
3654 | + |
3655 | + // Holds information about the currently ongoing touch input |
3656 | + touch = { |
3657 | + startX: 0, |
3658 | + startY: 0, |
3659 | + startSpan: 0, |
3660 | + startCount: 0, |
3661 | + captured: false, |
3662 | + threshold: 40 |
3663 | + }, |
3664 | + |
3665 | + // Holds information about the keyboard shortcuts |
3666 | + keyboardShortcuts = { |
3667 | + 'N , SPACE': 'Next slide', |
3668 | + 'P': 'Previous slide', |
3669 | + '← , H': 'Navigate left', |
3670 | + '→ , L': 'Navigate right', |
3671 | + '↑ , K': 'Navigate up', |
3672 | + '↓ , J': 'Navigate down', |
3673 | + 'Home': 'First slide', |
3674 | + 'End': 'Last slide', |
3675 | + 'B , .': 'Pause', |
3676 | + 'F': 'Fullscreen', |
3677 | + 'ESC, O': 'Slide overview' |
3678 | + }, |
3679 | + |
3680 | + // Holds custom key code mappings |
3681 | + registeredKeyBindings = {}; |
3682 | + |
3683 | + /** |
3684 | + * Starts up the presentation if the client is capable. |
3685 | + */ |
3686 | + function initialize( options ) { |
3687 | + |
3688 | + // Make sure we only initialize once |
3689 | + if( initialized === true ) return; |
3690 | + |
3691 | + initialized = true; |
3692 | + |
3693 | + checkCapabilities(); |
3694 | + |
3695 | + if( !features.transforms2d && !features.transforms3d ) { |
3696 | + document.body.setAttribute( 'class', 'no-transforms' ); |
3697 | + |
3698 | + // Since JS won't be running any further, we load all lazy |
3699 | + // loading elements upfront |
3700 | + var images = toArray( document.getElementsByTagName( 'img' ) ), |
3701 | + iframes = toArray( document.getElementsByTagName( 'iframe' ) ); |
3702 | + |
3703 | + var lazyLoadable = images.concat( iframes ); |
3704 | + |
3705 | + for( var i = 0, len = lazyLoadable.length; i < len; i++ ) { |
3706 | + var element = lazyLoadable[i]; |
3707 | + if( element.getAttribute( 'data-src' ) ) { |
3708 | + element.setAttribute( 'src', element.getAttribute( 'data-src' ) ); |
3709 | + element.removeAttribute( 'data-src' ); |
3710 | + } |
3711 | + } |
3712 | + |
3713 | + // If the browser doesn't support core features we won't be |
3714 | + // using JavaScript to control the presentation |
3715 | + return; |
3716 | + } |
3717 | + |
3718 | + // Cache references to key DOM elements |
3719 | + dom.wrapper = document.querySelector( '.reveal' ); |
3720 | + dom.slides = document.querySelector( '.reveal .slides' ); |
3721 | + |
3722 | + // Force a layout when the whole page, incl fonts, has loaded |
3723 | + window.addEventListener( 'load', layout, false ); |
3724 | + |
3725 | + var query = Reveal.getQueryHash(); |
3726 | + |
3727 | + // Do not accept new dependencies via query config to avoid |
3728 | + // the potential of malicious script injection |
3729 | + if( typeof query['dependencies'] !== 'undefined' ) delete query['dependencies']; |
3730 | + |
3731 | + // Copy options over to our config object |
3732 | + extend( config, options ); |
3733 | + extend( config, query ); |
3734 | + |
3735 | + // Hide the address bar in mobile browsers |
3736 | + hideAddressBar(); |
3737 | + |
3738 | + // Loads the dependencies and continues to #start() once done |
3739 | + load(); |
3740 | + |
3741 | + } |
3742 | + |
3743 | + /** |
3744 | + * Restarts up the presentation if the client is capable. |
3745 | + */ |
3746 | + function reinitialize() { |
3747 | + initialized = false; |
3748 | + initialize(config); |
3749 | + } |
3750 | + |
3751 | + /** |
3752 | + * Inspect the client to see what it's capable of, this |
3753 | + * should only happens once per runtime. |
3754 | + */ |
3755 | + function checkCapabilities() { |
3756 | + |
3757 | + isMobileDevice = /(iphone|ipod|ipad|android)/gi.test( UA ); |
3758 | + isChrome = /chrome/i.test( UA ) && !/edge/i.test( UA ); |
3759 | + |
3760 | + var testElement = document.createElement( 'div' ); |
3761 | + |
3762 | + features.transforms3d = 'WebkitPerspective' in testElement.style || |
3763 | + 'MozPerspective' in testElement.style || |
3764 | + 'msPerspective' in testElement.style || |
3765 | + 'OPerspective' in testElement.style || |
3766 | + 'perspective' in testElement.style; |
3767 | + |
3768 | + features.transforms2d = 'WebkitTransform' in testElement.style || |
3769 | + 'MozTransform' in testElement.style || |
3770 | + 'msTransform' in testElement.style || |
3771 | + 'OTransform' in testElement.style || |
3772 | + 'transform' in testElement.style; |
3773 | + |
3774 | + features.requestAnimationFrameMethod = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; |
3775 | + features.requestAnimationFrame = typeof features.requestAnimationFrameMethod === 'function'; |
3776 | + |
3777 | + features.canvas = !!document.createElement( 'canvas' ).getContext; |
3778 | + |
3779 | + // Transitions in the overview are disabled in desktop and |
3780 | + // Safari due to lag |
3781 | + features.overviewTransitions = !/Version\/[\d\.]+.*Safari/.test( UA ); |
3782 | + |
3783 | + // Flags if we should use zoom instead of transform to scale |
3784 | + // up slides. Zoom produces crisper results but has a lot of |
3785 | + // xbrowser quirks so we only use it in whitelsited browsers. |
3786 | + features.zoom = 'zoom' in testElement.style && !isMobileDevice && |
3787 | + ( isChrome || /Version\/[\d\.]+.*Safari/.test( UA ) ); |
3788 | + |
3789 | + } |
3790 | + |
3791 | + /** |
3792 | + * Loads the dependencies of reveal.js. Dependencies are |
3793 | + * defined via the configuration option 'dependencies' |
3794 | + * and will be loaded prior to starting/binding reveal.js. |
3795 | + * Some dependencies may have an 'async' flag, if so they |
3796 | + * will load after reveal.js has been started up. |
3797 | + */ |
3798 | + function load() { |
3799 | + |
3800 | + var scripts = [], |
3801 | + scriptsAsync = [], |
3802 | + scriptsToPreload = 0; |
3803 | + |
3804 | + // Called once synchronous scripts finish loading |
3805 | + function proceed() { |
3806 | + if( scriptsAsync.length ) { |
3807 | + // Load asynchronous scripts |
3808 | + head.js.apply( null, scriptsAsync ); |
3809 | + } |
3810 | + |
3811 | + start(); |
3812 | + } |
3813 | + |
3814 | + function loadScript( s ) { |
3815 | + head.ready( s.src.match( /([\w\d_\-]*)\.?js(\?[\w\d.=&]*)?$|[^\\\/]*$/i )[0], function() { |
3816 | + // Extension may contain callback functions |
3817 | + if( typeof s.callback === 'function' ) { |
3818 | + s.callback.apply( this ); |
3819 | + } |
3820 | + |
3821 | + if( --scriptsToPreload === 0 ) { |
3822 | + proceed(); |
3823 | + } |
3824 | + }); |
3825 | + } |
3826 | + |
3827 | + for( var i = 0, len = config.dependencies.length; i < len; i++ ) { |
3828 | + var s = config.dependencies[i]; |
3829 | + |
3830 | + // Load if there's no condition or the condition is truthy |
3831 | + if( !s.condition || s.condition() ) { |
3832 | + if( s.async ) { |
3833 | + scriptsAsync.push( s.src ); |
3834 | + } |
3835 | + else { |
3836 | + scripts.push( s.src ); |
3837 | + } |
3838 | + |
3839 | + loadScript( s ); |
3840 | + } |
3841 | + } |
3842 | + |
3843 | + if( scripts.length ) { |
3844 | + scriptsToPreload = scripts.length; |
3845 | + |
3846 | + // Load synchronous scripts |
3847 | + head.js.apply( null, scripts ); |
3848 | + } |
3849 | + else { |
3850 | + proceed(); |
3851 | + } |
3852 | + |
3853 | + } |
3854 | + |
3855 | + /** |
3856 | + * Starts up reveal.js by binding input events and navigating |
3857 | + * to the current URL deeplink if there is one. |
3858 | + */ |
3859 | + function start() { |
3860 | + |
3861 | + loaded = true; |
3862 | + |
3863 | + // Make sure we've got all the DOM elements we need |
3864 | + setupDOM(); |
3865 | + |
3866 | + // Listen to messages posted to this window |
3867 | + setupPostMessage(); |
3868 | + |
3869 | + // Prevent the slides from being scrolled out of view |
3870 | + setupScrollPrevention(); |
3871 | + |
3872 | + // Resets all vertical slides so that only the first is visible |
3873 | + resetVerticalSlides(); |
3874 | + |
3875 | + // Updates the presentation to match the current configuration values |
3876 | + configure(); |
3877 | + |
3878 | + // Read the initial hash |
3879 | + readURL(); |
3880 | + |
3881 | + // Update all backgrounds |
3882 | + updateBackground( true ); |
3883 | + |
3884 | + // Notify listeners that the presentation is ready but use a 1ms |
3885 | + // timeout to ensure it's not fired synchronously after #initialize() |
3886 | + setTimeout( function() { |
3887 | + // Enable transitions now that we're loaded |
3888 | + dom.slides.classList.remove( 'no-transition' ); |
3889 | + |
3890 | + dom.wrapper.classList.add( 'ready' ); |
3891 | + |
3892 | + dispatchEvent( 'ready', { |
3893 | + 'indexh': indexh, |
3894 | + 'indexv': indexv, |
3895 | + 'currentSlide': currentSlide |
3896 | + } ); |
3897 | + }, 1 ); |
3898 | + |
3899 | + // Special setup and config is required when printing to PDF |
3900 | + if( isPrintingPDF() ) { |
3901 | + removeEventListeners(); |
3902 | + |
3903 | + // The document needs to have loaded for the PDF layout |
3904 | + // measurements to be accurate |
3905 | + if( document.readyState === 'complete' ) { |
3906 | + setupPDF(); |
3907 | + } |
3908 | + else { |
3909 | + window.addEventListener( 'load', setupPDF ); |
3910 | + } |
3911 | + } |
3912 | + |
3913 | + } |
3914 | + |
3915 | + /** |
3916 | + * Finds and stores references to DOM elements which are |
3917 | + * required by the presentation. If a required element is |
3918 | + * not found, it is created. |
3919 | + */ |
3920 | + function setupDOM() { |
3921 | + |
3922 | + // Prevent transitions while we're loading |
3923 | + dom.slides.classList.add( 'no-transition' ); |
3924 | + |
3925 | + if( isMobileDevice ) { |
3926 | + dom.wrapper.classList.add( 'no-hover' ); |
3927 | + } |
3928 | + else { |
3929 | + dom.wrapper.classList.remove( 'no-hover' ); |
3930 | + } |
3931 | + |
3932 | + if( /iphone/gi.test( UA ) ) { |
3933 | + dom.wrapper.classList.add( 'ua-iphone' ); |
3934 | + } |
3935 | + else { |
3936 | + dom.wrapper.classList.remove( 'ua-iphone' ); |
3937 | + } |
3938 | + |
3939 | + // Background element |
3940 | + dom.background = createSingletonNode( dom.wrapper, 'div', 'backgrounds', null ); |
3941 | + |
3942 | + // Progress bar |
3943 | + dom.progress = createSingletonNode( dom.wrapper, 'div', 'progress', '<span></span>' ); |
3944 | + dom.progressbar = dom.progress.querySelector( 'span' ); |
3945 | + |
3946 | + // Arrow controls |
3947 | + dom.controls = createSingletonNode( dom.wrapper, 'aside', 'controls', |
3948 | + '<button class="navigate-left" aria-label="previous slide"><div class="controls-arrow"></div></button>' + |
3949 | + '<button class="navigate-right" aria-label="next slide"><div class="controls-arrow"></div></button>' + |
3950 | + '<button class="navigate-up" aria-label="above slide"><div class="controls-arrow"></div></button>' + |
3951 | + '<button class="navigate-down" aria-label="below slide"><div class="controls-arrow"></div></button>' ); |
3952 | + |
3953 | + // Slide number |
3954 | + dom.slideNumber = createSingletonNode( dom.wrapper, 'div', 'slide-number', '' ); |
3955 | + |
3956 | + // Element containing notes that are visible to the audience |
3957 | + dom.speakerNotes = createSingletonNode( dom.wrapper, 'div', 'speaker-notes', null ); |
3958 | + dom.speakerNotes.setAttribute( 'data-prevent-swipe', '' ); |
3959 | + dom.speakerNotes.setAttribute( 'tabindex', '0' ); |
3960 | + |
3961 | + // Overlay graphic which is displayed during the paused mode |
3962 | + dom.pauseOverlay = createSingletonNode( dom.wrapper, 'div', 'pause-overlay', '<button class="resume-button">Resume presentation</button>' ); |
3963 | + dom.resumeButton = dom.pauseOverlay.querySelector( '.resume-button' ); |
3964 | + |
3965 | + dom.wrapper.setAttribute( 'role', 'application' ); |
3966 | + |
3967 | + // There can be multiple instances of controls throughout the page |
3968 | + dom.controlsLeft = toArray( document.querySelectorAll( '.navigate-left' ) ); |
3969 | + dom.controlsRight = toArray( document.querySelectorAll( '.navigate-right' ) ); |
3970 | + dom.controlsUp = toArray( document.querySelectorAll( '.navigate-up' ) ); |
3971 | + dom.controlsDown = toArray( document.querySelectorAll( '.navigate-down' ) ); |
3972 | + dom.controlsPrev = toArray( document.querySelectorAll( '.navigate-prev' ) ); |
3973 | + dom.controlsNext = toArray( document.querySelectorAll( '.navigate-next' ) ); |
3974 | + |
3975 | + // The right and down arrows in the standard reveal.js controls |
3976 | + dom.controlsRightArrow = dom.controls.querySelector( '.navigate-right' ); |
3977 | + dom.controlsDownArrow = dom.controls.querySelector( '.navigate-down' ); |
3978 | + |
3979 | + dom.statusDiv = createStatusDiv(); |
3980 | + } |
3981 | + |
3982 | + /** |
3983 | + * Creates a hidden div with role aria-live to announce the |
3984 | + * current slide content. Hide the div off-screen to make it |
3985 | + * available only to Assistive Technologies. |
3986 | + * |
3987 | + * @return {HTMLElement} |
3988 | + */ |
3989 | + function createStatusDiv() { |
3990 | + |
3991 | + var statusDiv = document.getElementById( 'aria-status-div' ); |
3992 | + if( !statusDiv ) { |
3993 | + statusDiv = document.createElement( 'div' ); |
3994 | + statusDiv.style.position = 'absolute'; |
3995 | + statusDiv.style.height = '1px'; |
3996 | + statusDiv.style.width = '1px'; |
3997 | + statusDiv.style.overflow = 'hidden'; |
3998 | + statusDiv.style.clip = 'rect( 1px, 1px, 1px, 1px )'; |
3999 | + statusDiv.setAttribute( 'id', 'aria-status-div' ); |
4000 | + statusDiv.setAttribute( 'aria-live', 'polite' ); |
4001 | + statusDiv.setAttribute( 'aria-atomic','true' ); |
4002 | + dom.wrapper.appendChild( statusDiv ); |
4003 | + } |
4004 | + return statusDiv; |
4005 | + |
4006 | + } |
4007 | + |
4008 | + /** |
4009 | + * Converts the given HTML element into a string of text |
4010 | + * that can be announced to a screen reader. Hidden |
4011 | + * elements are excluded. |
4012 | + */ |
4013 | + function getStatusText( node ) { |
4014 | + |
4015 | + var text = ''; |
4016 | + |
4017 | + // Text node |
4018 | + if( node.nodeType === 3 ) { |
4019 | + text += node.textContent; |
4020 | + } |
4021 | + // Element node |
4022 | + else if( node.nodeType === 1 ) { |
4023 | + |
4024 | + var isAriaHidden = node.getAttribute( 'aria-hidden' ); |
4025 | + var isDisplayHidden = window.getComputedStyle( node )['display'] === 'none'; |
4026 | + if( isAriaHidden !== 'true' && !isDisplayHidden ) { |
4027 | + |
4028 | + toArray( node.childNodes ).forEach( function( child ) { |
4029 | + text += getStatusText( child ); |
4030 | + } ); |
4031 | + |
4032 | + } |
4033 | + |
4034 | + } |
4035 | + |
4036 | + return text; |
4037 | + |
4038 | + } |
4039 | + |
4040 | + /** |
4041 | + * Configures the presentation for printing to a static |
4042 | + * PDF. |
4043 | + */ |
4044 | + function setupPDF() { |
4045 | + |
4046 | + var slideSize = getComputedSlideSize( window.innerWidth, window.innerHeight ); |
4047 | + |
4048 | + // Dimensions of the PDF pages |
4049 | + var pageWidth = Math.floor( slideSize.width * ( 1 + config.margin ) ), |
4050 | + pageHeight = Math.floor( slideSize.height * ( 1 + config.margin ) ); |
4051 | + |
4052 | + // Dimensions of slides within the pages |
4053 | + var slideWidth = slideSize.width, |
4054 | + slideHeight = slideSize.height; |
4055 | + |
4056 | + // Let the browser know what page size we want to print |
4057 | + injectStyleSheet( '@page{size:'+ pageWidth +'px '+ pageHeight +'px; margin: 0px;}' ); |
4058 | + |
4059 | + // Limit the size of certain elements to the dimensions of the slide |
4060 | + injectStyleSheet( '.reveal section>img, .reveal section>video, .reveal section>iframe{max-width: '+ slideWidth +'px; max-height:'+ slideHeight +'px}' ); |
4061 | + |
4062 | + document.body.classList.add( 'print-pdf' ); |
4063 | + document.body.style.width = pageWidth + 'px'; |
4064 | + document.body.style.height = pageHeight + 'px'; |
4065 | + |
4066 | + // Make sure stretch elements fit on slide |
4067 | + layoutSlideContents( slideWidth, slideHeight ); |
4068 | + |
4069 | + // Add each slide's index as attributes on itself, we need these |
4070 | + // indices to generate slide numbers below |
4071 | + toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( hslide, h ) { |
4072 | + hslide.setAttribute( 'data-index-h', h ); |
4073 | + |
4074 | + if( hslide.classList.contains( 'stack' ) ) { |
4075 | + toArray( hslide.querySelectorAll( 'section' ) ).forEach( function( vslide, v ) { |
4076 | + vslide.setAttribute( 'data-index-h', h ); |
4077 | + vslide.setAttribute( 'data-index-v', v ); |
4078 | + } ); |
4079 | + } |
4080 | + } ); |
4081 | + |
4082 | + // Slide and slide background layout |
4083 | + toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) { |
4084 | + |
4085 | + // Vertical stacks are not centred since their section |
4086 | + // children will be |
4087 | + if( slide.classList.contains( 'stack' ) === false ) { |
4088 | + // Center the slide inside of the page, giving the slide some margin |
4089 | + var left = ( pageWidth - slideWidth ) / 2, |
4090 | + top = ( pageHeight - slideHeight ) / 2; |
4091 | + |
4092 | + var contentHeight = slide.scrollHeight; |
4093 | + var numberOfPages = Math.max( Math.ceil( contentHeight / pageHeight ), 1 ); |
4094 | + |
4095 | + // Adhere to configured pages per slide limit |
4096 | + numberOfPages = Math.min( numberOfPages, config.pdfMaxPagesPerSlide ); |
4097 | + |
4098 | + // Center slides vertically |
4099 | + if( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) { |
4100 | + top = Math.max( ( pageHeight - contentHeight ) / 2, 0 ); |
4101 | + } |
4102 | + |
4103 | + // Wrap the slide in a page element and hide its overflow |
4104 | + // so that no page ever flows onto another |
4105 | + var page = document.createElement( 'div' ); |
4106 | + page.className = 'pdf-page'; |
4107 | + page.style.height = ( ( pageHeight + config.pdfPageHeightOffset ) * numberOfPages ) + 'px'; |
4108 | + slide.parentNode.insertBefore( page, slide ); |
4109 | + page.appendChild( slide ); |
4110 | + |
4111 | + // Position the slide inside of the page |
4112 | + slide.style.left = left + 'px'; |
4113 | + slide.style.top = top + 'px'; |
4114 | + slide.style.width = slideWidth + 'px'; |
4115 | + |
4116 | + if( slide.slideBackgroundElement ) { |
4117 | + page.insertBefore( slide.slideBackgroundElement, slide ); |
4118 | + } |
4119 | + |
4120 | + // Inject notes if `showNotes` is enabled |
4121 | + if( config.showNotes ) { |
4122 | + |
4123 | + // Are there notes for this slide? |
4124 | + var notes = getSlideNotes( slide ); |
4125 | + if( notes ) { |
4126 | + |
4127 | + var notesSpacing = 8; |
4128 | + var notesLayout = typeof config.showNotes === 'string' ? config.showNotes : 'inline'; |
4129 | + var notesElement = document.createElement( 'div' ); |
4130 | + notesElement.classList.add( 'speaker-notes' ); |
4131 | + notesElement.classList.add( 'speaker-notes-pdf' ); |
4132 | + notesElement.setAttribute( 'data-layout', notesLayout ); |
4133 | + notesElement.innerHTML = notes; |
4134 | + |
4135 | + if( notesLayout === 'separate-page' ) { |
4136 | + page.parentNode.insertBefore( notesElement, page.nextSibling ); |
4137 | + } |
4138 | + else { |
4139 | + notesElement.style.left = notesSpacing + 'px'; |
4140 | + notesElement.style.bottom = notesSpacing + 'px'; |
4141 | + notesElement.style.width = ( pageWidth - notesSpacing*2 ) + 'px'; |
4142 | + page.appendChild( notesElement ); |
4143 | + } |
4144 | + |
4145 | + } |
4146 | + |
4147 | + } |
4148 | + |
4149 | + // Inject slide numbers if `slideNumbers` are enabled |
4150 | + if( config.slideNumber && /all|print/i.test( config.showSlideNumber ) ) { |
4151 | + var slideNumberH = parseInt( slide.getAttribute( 'data-index-h' ), 10 ) + 1, |
4152 | + slideNumberV = parseInt( slide.getAttribute( 'data-index-v' ), 10 ) + 1; |
4153 | + |
4154 | + var numberElement = document.createElement( 'div' ); |
4155 | + numberElement.classList.add( 'slide-number' ); |
4156 | + numberElement.classList.add( 'slide-number-pdf' ); |
4157 | + numberElement.innerHTML = formatSlideNumber( slideNumberH, '.', slideNumberV ); |
4158 | + page.appendChild( numberElement ); |
4159 | + } |
4160 | + |
4161 | + // Copy page and show fragments one after another |
4162 | + if( config.pdfSeparateFragments ) { |
4163 | + |
4164 | + // Each fragment 'group' is an array containing one or more |
4165 | + // fragments. Multiple fragments that appear at the same time |
4166 | + // are part of the same group. |
4167 | + var fragmentGroups = sortFragments( page.querySelectorAll( '.fragment' ), true ); |
4168 | + |
4169 | + var previousFragmentStep; |
4170 | + var previousPage; |
4171 | + |
4172 | + fragmentGroups.forEach( function( fragments ) { |
4173 | + |
4174 | + // Remove 'current-fragment' from the previous group |
4175 | + if( previousFragmentStep ) { |
4176 | + previousFragmentStep.forEach( function( fragment ) { |
4177 | + fragment.classList.remove( 'current-fragment' ); |
4178 | + } ); |
4179 | + } |
4180 | + |
4181 | + // Show the fragments for the current index |
4182 | + fragments.forEach( function( fragment ) { |
4183 | + fragment.classList.add( 'visible', 'current-fragment' ); |
4184 | + } ); |
4185 | + |
4186 | + // Create a separate page for the current fragment state |
4187 | + var clonedPage = page.cloneNode( true ); |
4188 | + page.parentNode.insertBefore( clonedPage, ( previousPage || page ).nextSibling ); |
4189 | + |
4190 | + previousFragmentStep = fragments; |
4191 | + previousPage = clonedPage; |
4192 | + |
4193 | + } ); |
4194 | + |
4195 | + // Reset the first/original page so that all fragments are hidden |
4196 | + fragmentGroups.forEach( function( fragments ) { |
4197 | + fragments.forEach( function( fragment ) { |
4198 | + fragment.classList.remove( 'visible', 'current-fragment' ); |
4199 | + } ); |
4200 | + } ); |
4201 | + |
4202 | + } |
4203 | + // Show all fragments |
4204 | + else { |
4205 | + toArray( page.querySelectorAll( '.fragment:not(.fade-out)' ) ).forEach( function( fragment ) { |
4206 | + fragment.classList.add( 'visible' ); |
4207 | + } ); |
4208 | + } |
4209 | + |
4210 | + } |
4211 | + |
4212 | + } ); |
4213 | + |
4214 | + // Notify subscribers that the PDF layout is good to go |
4215 | + dispatchEvent( 'pdf-ready' ); |
4216 | + |
4217 | + } |
4218 | + |
4219 | + /** |
4220 | + * This is an unfortunate necessity. Some actions – such as |
4221 | + * an input field being focused in an iframe or using the |
4222 | + * keyboard to expand text selection beyond the bounds of |
4223 | + * a slide – can trigger our content to be pushed out of view. |
4224 | + * This scrolling can not be prevented by hiding overflow in |
4225 | + * CSS (we already do) so we have to resort to repeatedly |
4226 | + * checking if the slides have been offset :( |
4227 | + */ |
4228 | + function setupScrollPrevention() { |
4229 | + |
4230 | + setInterval( function() { |
4231 | + if( dom.wrapper.scrollTop !== 0 || dom.wrapper.scrollLeft !== 0 ) { |
4232 | + dom.wrapper.scrollTop = 0; |
4233 | + dom.wrapper.scrollLeft = 0; |
4234 | + } |
4235 | + }, 1000 ); |
4236 | + |
4237 | + } |
4238 | + |
4239 | + /** |
4240 | + * Creates an HTML element and returns a reference to it. |
4241 | + * If the element already exists the existing instance will |
4242 | + * be returned. |
4243 | + * |
4244 | + * @param {HTMLElement} container |
4245 | + * @param {string} tagname |
4246 | + * @param {string} classname |
4247 | + * @param {string} innerHTML |
4248 | + * |
4249 | + * @return {HTMLElement} |
4250 | + */ |
4251 | + function createSingletonNode( container, tagname, classname, innerHTML ) { |
4252 | + |
4253 | + // Find all nodes matching the description |
4254 | + var nodes = container.querySelectorAll( '.' + classname ); |
4255 | + |
4256 | + // Check all matches to find one which is a direct child of |
4257 | + // the specified container |
4258 | + for( var i = 0; i < nodes.length; i++ ) { |
4259 | + var testNode = nodes[i]; |
4260 | + if( testNode.parentNode === container ) { |
4261 | + return testNode; |
4262 | + } |
4263 | + } |
4264 | + |
4265 | + // If no node was found, create it now |
4266 | + var node = document.createElement( tagname ); |
4267 | + node.className = classname; |
4268 | + if( typeof innerHTML === 'string' ) { |
4269 | + node.innerHTML = innerHTML; |
4270 | + } |
4271 | + container.appendChild( node ); |
4272 | + |
4273 | + return node; |
4274 | + |
4275 | + } |
4276 | + |
4277 | + /** |
4278 | + * Creates the slide background elements and appends them |
4279 | + * to the background container. One element is created per |
4280 | + * slide no matter if the given slide has visible background. |
4281 | + */ |
4282 | + function createBackgrounds() { |
4283 | + |
4284 | + var printMode = isPrintingPDF(); |
4285 | + |
4286 | + // Clear prior backgrounds |
4287 | + dom.background.innerHTML = ''; |
4288 | + dom.background.classList.add( 'no-transition' ); |
4289 | + |
4290 | + // Iterate over all horizontal slides |
4291 | + toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( slideh ) { |
4292 | + |
4293 | + var backgroundStack = createBackground( slideh, dom.background ); |
4294 | + |
4295 | + // Iterate over all vertical slides |
4296 | + toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) { |
4297 | + |
4298 | + createBackground( slidev, backgroundStack ); |
4299 | + |
4300 | + backgroundStack.classList.add( 'stack' ); |
4301 | + |
4302 | + } ); |
4303 | + |
4304 | + } ); |
4305 | + |
4306 | + // Add parallax background if specified |
4307 | + if( config.parallaxBackgroundImage ) { |
4308 | + |
4309 | + dom.background.style.backgroundImage = 'url("' + config.parallaxBackgroundImage + '")'; |
4310 | + dom.background.style.backgroundSize = config.parallaxBackgroundSize; |
4311 | + dom.background.style.backgroundRepeat = config.parallaxBackgroundRepeat; |
4312 | + dom.background.style.backgroundPosition = config.parallaxBackgroundPosition; |
4313 | + |
4314 | + // Make sure the below properties are set on the element - these properties are |
4315 | + // needed for proper transitions to be set on the element via CSS. To remove |
4316 | + // annoying background slide-in effect when the presentation starts, apply |
4317 | + // these properties after short time delay |
4318 | + setTimeout( function() { |
4319 | + dom.wrapper.classList.add( 'has-parallax-background' ); |
4320 | + }, 1 ); |
4321 | + |
4322 | + } |
4323 | + else { |
4324 | + |
4325 | + dom.background.style.backgroundImage = ''; |
4326 | + dom.wrapper.classList.remove( 'has-parallax-background' ); |
4327 | + |
4328 | + } |
4329 | + |
4330 | + } |
4331 | + |
4332 | + /** |
4333 | + * Creates a background for the given slide. |
4334 | + * |
4335 | + * @param {HTMLElement} slide |
4336 | + * @param {HTMLElement} container The element that the background |
4337 | + * should be appended to |
4338 | + * @return {HTMLElement} New background div |
4339 | + */ |
4340 | + function createBackground( slide, container ) { |
4341 | + |
4342 | + |
4343 | + // Main slide background element |
4344 | + var element = document.createElement( 'div' ); |
4345 | + element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' ); |
4346 | + |
4347 | + // Inner background element that wraps images/videos/iframes |
4348 | + var contentElement = document.createElement( 'div' ); |
4349 | + contentElement.className = 'slide-background-content'; |
4350 | + |
4351 | + element.appendChild( contentElement ); |
4352 | + container.appendChild( element ); |
4353 | + |
4354 | + slide.slideBackgroundElement = element; |
4355 | + slide.slideBackgroundContentElement = contentElement; |
4356 | + |
4357 | + // Syncs the background to reflect all current background settings |
4358 | + syncBackground( slide ); |
4359 | + |
4360 | + return element; |
4361 | + |
4362 | + } |
4363 | + |
4364 | + /** |
4365 | + * Renders all of the visual properties of a slide background |
4366 | + * based on the various background attributes. |
4367 | + * |
4368 | + * @param {HTMLElement} slide |
4369 | + */ |
4370 | + function syncBackground( slide ) { |
4371 | + |
4372 | + var element = slide.slideBackgroundElement, |
4373 | + contentElement = slide.slideBackgroundContentElement; |
4374 | + |
4375 | + // Reset the prior background state in case this is not the |
4376 | + // initial sync |
4377 | + slide.classList.remove( 'has-dark-background' ); |
4378 | + slide.classList.remove( 'has-light-background' ); |
4379 | + |
4380 | + element.removeAttribute( 'data-loaded' ); |
4381 | + element.removeAttribute( 'data-background-hash' ); |
4382 | + element.removeAttribute( 'data-background-size' ); |
4383 | + element.removeAttribute( 'data-background-transition' ); |
4384 | + element.style.backgroundColor = ''; |
4385 | + |
4386 | + contentElement.style.backgroundSize = ''; |
4387 | + contentElement.style.backgroundRepeat = ''; |
4388 | + contentElement.style.backgroundPosition = ''; |
4389 | + contentElement.style.backgroundImage = ''; |
4390 | + contentElement.style.opacity = ''; |
4391 | + contentElement.innerHTML = ''; |
4392 | + |
4393 | + var data = { |
4394 | + background: slide.getAttribute( 'data-background' ), |
4395 | + backgroundSize: slide.getAttribute( 'data-background-size' ), |
4396 | + backgroundImage: slide.getAttribute( 'data-background-image' ), |
4397 | + backgroundVideo: slide.getAttribute( 'data-background-video' ), |
4398 | + backgroundIframe: slide.getAttribute( 'data-background-iframe' ), |
4399 | + backgroundColor: slide.getAttribute( 'data-background-color' ), |
4400 | + backgroundRepeat: slide.getAttribute( 'data-background-repeat' ), |
4401 | + backgroundPosition: slide.getAttribute( 'data-background-position' ), |
4402 | + backgroundTransition: slide.getAttribute( 'data-background-transition' ), |
4403 | + backgroundOpacity: slide.getAttribute( 'data-background-opacity' ) |
4404 | + }; |
4405 | + |
4406 | + if( data.background ) { |
4407 | + // Auto-wrap image urls in url(...) |
4408 | + if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)([?#\s]|$)/gi.test( data.background ) ) { |
4409 | + slide.setAttribute( 'data-background-image', data.background ); |
4410 | + } |
4411 | + else { |
4412 | + element.style.background = data.background; |
4413 | + } |
4414 | + } |
4415 | + |
4416 | + // Create a hash for this combination of background settings. |
4417 | + // This is used to determine when two slide backgrounds are |
4418 | + // the same. |
4419 | + if( data.background || data.backgroundColor || data.backgroundImage || data.backgroundVideo || data.backgroundIframe ) { |
4420 | + element.setAttribute( 'data-background-hash', data.background + |
4421 | + data.backgroundSize + |
4422 | + data.backgroundImage + |
4423 | + data.backgroundVideo + |
4424 | + data.backgroundIframe + |
4425 | + data.backgroundColor + |
4426 | + data.backgroundRepeat + |
4427 | + data.backgroundPosition + |
4428 | + data.backgroundTransition + |
4429 | + data.backgroundOpacity ); |
4430 | + } |
4431 | + |
4432 | + // Additional and optional background properties |
4433 | + if( data.backgroundSize ) element.setAttribute( 'data-background-size', data.backgroundSize ); |
4434 | + if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor; |
4435 | + if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition ); |
4436 | + |
4437 | + // Background image options are set on the content wrapper |
4438 | + if( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize; |
4439 | + if( data.backgroundRepeat ) contentElement.style.backgroundRepeat = data.backgroundRepeat; |
4440 | + if( data.backgroundPosition ) contentElement.style.backgroundPosition = data.backgroundPosition; |
4441 | + if( data.backgroundOpacity ) contentElement.style.opacity = data.backgroundOpacity; |
4442 | + |
4443 | + // If this slide has a background color, add a class that |
4444 | + // signals if it is light or dark. If the slide has no background |
4445 | + // color, no class will be set |
4446 | + var computedBackgroundStyle = window.getComputedStyle( element ); |
4447 | + if( computedBackgroundStyle && computedBackgroundStyle.backgroundColor ) { |
4448 | + var rgb = colorToRgb( computedBackgroundStyle.backgroundColor ); |
4449 | + |
4450 | + // Ignore fully transparent backgrounds. Some browsers return |
4451 | + // rgba(0,0,0,0) when reading the computed background color of |
4452 | + // an element with no background |
4453 | + if( rgb && rgb.a !== 0 ) { |
4454 | + if( colorBrightness( computedBackgroundStyle.backgroundColor ) < 128 ) { |
4455 | + slide.classList.add( 'has-dark-background' ); |
4456 | + } |
4457 | + else { |
4458 | + slide.classList.add( 'has-light-background' ); |
4459 | + } |
4460 | + } |
4461 | + } |
4462 | + |
4463 | + } |
4464 | + |
4465 | + /** |
4466 | + * Registers a listener to postMessage events, this makes it |
4467 | + * possible to call all reveal.js API methods from another |
4468 | + * window. For example: |
4469 | + * |
4470 | + * revealWindow.postMessage( JSON.stringify({ |
4471 | + * method: 'slide', |
4472 | + * args: [ 2 ] |
4473 | + * }), '*' ); |
4474 | + */ |
4475 | + function setupPostMessage() { |
4476 | + |
4477 | + if( config.postMessage ) { |
4478 | + window.addEventListener( 'message', function ( event ) { |
4479 | + var data = event.data; |
4480 | + |
4481 | + // Make sure we're dealing with JSON |
4482 | + if( typeof data === 'string' && data.charAt( 0 ) === '{' && data.charAt( data.length - 1 ) === '}' ) { |
4483 | + data = JSON.parse( data ); |
4484 | + |
4485 | + // Check if the requested method can be found |
4486 | + if( data.method && typeof Reveal[data.method] === 'function' ) { |
4487 | + Reveal[data.method].apply( Reveal, data.args ); |
4488 | + } |
4489 | + } |
4490 | + }, false ); |
4491 | + } |
4492 | + |
4493 | + } |
4494 | + |
4495 | + /** |
4496 | + * Applies the configuration settings from the config |
4497 | + * object. May be called multiple times. |
4498 | + * |
4499 | + * @param {object} options |
4500 | + */ |
4501 | + function configure( options ) { |
4502 | + |
4503 | + var oldTransition = config.transition; |
4504 | + |
4505 | + // New config options may be passed when this method |
4506 | + // is invoked through the API after initialization |
4507 | + if( typeof options === 'object' ) extend( config, options ); |
4508 | + |
4509 | + // Abort if reveal.js hasn't finished loading, config |
4510 | + // changes will be applied automatically once loading |
4511 | + // finishes |
4512 | + if( loaded === false ) return; |
4513 | + |
4514 | + var numberOfSlides = dom.wrapper.querySelectorAll( SLIDES_SELECTOR ).length; |
4515 | + |
4516 | + // Remove the previously configured transition class |
4517 | + dom.wrapper.classList.remove( oldTransition ); |
4518 | + |
4519 | + // Force linear transition based on browser capabilities |
4520 | + if( features.transforms3d === false ) config.transition = 'linear'; |
4521 | + |
4522 | + dom.wrapper.classList.add( config.transition ); |
4523 | + |
4524 | + dom.wrapper.setAttribute( 'data-transition-speed', config.transitionSpeed ); |
4525 | + dom.wrapper.setAttribute( 'data-background-transition', config.backgroundTransition ); |
4526 | + |
4527 | + dom.controls.style.display = config.controls ? 'block' : 'none'; |
4528 | + dom.progress.style.display = config.progress ? 'block' : 'none'; |
4529 | + |
4530 | + dom.controls.setAttribute( 'data-controls-layout', config.controlsLayout ); |
4531 | + dom.controls.setAttribute( 'data-controls-back-arrows', config.controlsBackArrows ); |
4532 | + |
4533 | + if( config.shuffle ) { |
4534 | + shuffle(); |
4535 | + } |
4536 | + |
4537 | + if( config.rtl ) { |
4538 | + dom.wrapper.classList.add( 'rtl' ); |
4539 | + } |
4540 | + else { |
4541 | + dom.wrapper.classList.remove( 'rtl' ); |
4542 | + } |
4543 | + |
4544 | + if( config.center ) { |
4545 | + dom.wrapper.classList.add( 'center' ); |
4546 | + } |
4547 | + else { |
4548 | + dom.wrapper.classList.remove( 'center' ); |
4549 | + } |
4550 | + |
4551 | + // Exit the paused mode if it was configured off |
4552 | + if( config.pause === false ) { |
4553 | + resume(); |
4554 | + } |
4555 | + |
4556 | + if( config.showNotes ) { |
4557 | + dom.speakerNotes.setAttribute( 'data-layout', typeof config.showNotes === 'string' ? config.showNotes : 'inline' ); |
4558 | + } |
4559 | + |
4560 | + if( config.mouseWheel ) { |
4561 | + document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF |
4562 | + document.addEventListener( 'mousewheel', onDocumentMouseScroll, false ); |
4563 | + } |
4564 | + else { |
4565 | + document.removeEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF |
4566 | + document.removeEventListener( 'mousewheel', onDocumentMouseScroll, false ); |
4567 | + } |
4568 | + |
4569 | + // Rolling 3D links |
4570 | + if( config.rollingLinks ) { |
4571 | + enableRollingLinks(); |
4572 | + } |
4573 | + else { |
4574 | + disableRollingLinks(); |
4575 | + } |
4576 | + |
4577 | + // Iframe link previews |
4578 | + if( config.previewLinks ) { |
4579 | + enablePreviewLinks(); |
4580 | + disablePreviewLinks( '[data-preview-link=false]' ); |
4581 | + } |
4582 | + else { |
4583 | + disablePreviewLinks(); |
4584 | + enablePreviewLinks( '[data-preview-link]:not([data-preview-link=false])' ); |
4585 | + } |
4586 | + |
4587 | + // Remove existing auto-slide controls |
4588 | + if( autoSlidePlayer ) { |
4589 | + autoSlidePlayer.destroy(); |
4590 | + autoSlidePlayer = null; |
4591 | + } |
4592 | + |
4593 | + // Generate auto-slide controls if needed |
4594 | + if( numberOfSlides > 1 && config.autoSlide && config.autoSlideStoppable && features.canvas && features.requestAnimationFrame ) { |
4595 | + autoSlidePlayer = new Playback( dom.wrapper, function() { |
4596 | + return Math.min( Math.max( ( Date.now() - autoSlideStartTime ) / autoSlide, 0 ), 1 ); |
4597 | + } ); |
4598 | + |
4599 | + autoSlidePlayer.on( 'click', onAutoSlidePlayerClick ); |
4600 | + autoSlidePaused = false; |
4601 | + } |
4602 | + |
4603 | + // When fragments are turned off they should be visible |
4604 | + if( config.fragments === false ) { |
4605 | + toArray( dom.slides.querySelectorAll( '.fragment' ) ).forEach( function( element ) { |
4606 | + element.classList.add( 'visible' ); |
4607 | + element.classList.remove( 'current-fragment' ); |
4608 | + } ); |
4609 | + } |
4610 | + |
4611 | + // Slide numbers |
4612 | + var slideNumberDisplay = 'none'; |
4613 | + if( config.slideNumber && !isPrintingPDF() ) { |
4614 | + if( config.showSlideNumber === 'all' ) { |
4615 | + slideNumberDisplay = 'block'; |
4616 | + } |
4617 | + else if( config.showSlideNumber === 'speaker' && isSpeakerNotes() ) { |
4618 | + slideNumberDisplay = 'block'; |
4619 | + } |
4620 | + } |
4621 | + |
4622 | + dom.slideNumber.style.display = slideNumberDisplay; |
4623 | + |
4624 | + sync(); |
4625 | + |
4626 | + } |
4627 | + |
4628 | + /** |
4629 | + * Binds all event listeners. |
4630 | + */ |
4631 | + function addEventListeners() { |
4632 | + |
4633 | + eventsAreBound = true; |
4634 | + |
4635 | + window.addEventListener( 'hashchange', onWindowHashChange, false ); |
4636 | + window.addEventListener( 'resize', onWindowResize, false ); |
4637 | + |
4638 | + if( config.touch ) { |
4639 | + if( 'onpointerdown' in window ) { |
4640 | + // Use W3C pointer events |
4641 | + dom.wrapper.addEventListener( 'pointerdown', onPointerDown, false ); |
4642 | + dom.wrapper.addEventListener( 'pointermove', onPointerMove, false ); |
4643 | + dom.wrapper.addEventListener( 'pointerup', onPointerUp, false ); |
4644 | + } |
4645 | + else if( window.navigator.msPointerEnabled ) { |
4646 | + // IE 10 uses prefixed version of pointer events |
4647 | + dom.wrapper.addEventListener( 'MSPointerDown', onPointerDown, false ); |
4648 | + dom.wrapper.addEventListener( 'MSPointerMove', onPointerMove, false ); |
4649 | + dom.wrapper.addEventListener( 'MSPointerUp', onPointerUp, false ); |
4650 | + } |
4651 | + else { |
4652 | + // Fall back to touch events |
4653 | + dom.wrapper.addEventListener( 'touchstart', onTouchStart, false ); |
4654 | + dom.wrapper.addEventListener( 'touchmove', onTouchMove, false ); |
4655 | + dom.wrapper.addEventListener( 'touchend', onTouchEnd, false ); |
4656 | + } |
4657 | + } |
4658 | + |
4659 | + if( config.keyboard ) { |
4660 | + document.addEventListener( 'keydown', onDocumentKeyDown, false ); |
4661 | + document.addEventListener( 'keypress', onDocumentKeyPress, false ); |
4662 | + } |
4663 | + |
4664 | + if( config.progress && dom.progress ) { |
4665 | + dom.progress.addEventListener( 'click', onProgressClicked, false ); |
4666 | + } |
4667 | + |
4668 | + dom.resumeButton.addEventListener( 'click', resume, false ); |
4669 | + |
4670 | + if( config.focusBodyOnPageVisibilityChange ) { |
4671 | + var visibilityChange; |
4672 | + |
4673 | + if( 'hidden' in document ) { |
4674 | + visibilityChange = 'visibilitychange'; |
4675 | + } |
4676 | + else if( 'msHidden' in document ) { |
4677 | + visibilityChange = 'msvisibilitychange'; |
4678 | + } |
4679 | + else if( 'webkitHidden' in document ) { |
4680 | + visibilityChange = 'webkitvisibilitychange'; |
4681 | + } |
4682 | + |
4683 | + if( visibilityChange ) { |
4684 | + document.addEventListener( visibilityChange, onPageVisibilityChange, false ); |
4685 | + } |
4686 | + } |
4687 | + |
4688 | + // Listen to both touch and click events, in case the device |
4689 | + // supports both |
4690 | + var pointerEvents = [ 'touchstart', 'click' ]; |
4691 | + |
4692 | + // Only support touch for Android, fixes double navigations in |
4693 | + // stock browser |
4694 | + if( UA.match( /android/gi ) ) { |
4695 | + pointerEvents = [ 'touchstart' ]; |
4696 | + } |
4697 | + |
4698 | + pointerEvents.forEach( function( eventName ) { |
4699 | + dom.controlsLeft.forEach( function( el ) { el.addEventListener( eventName, onNavigateLeftClicked, false ); } ); |
4700 | + dom.controlsRight.forEach( function( el ) { el.addEventListener( eventName, onNavigateRightClicked, false ); } ); |
4701 | + dom.controlsUp.forEach( function( el ) { el.addEventListener( eventName, onNavigateUpClicked, false ); } ); |
4702 | + dom.controlsDown.forEach( function( el ) { el.addEventListener( eventName, onNavigateDownClicked, false ); } ); |
4703 | + dom.controlsPrev.forEach( function( el ) { el.addEventListener( eventName, onNavigatePrevClicked, false ); } ); |
4704 | + dom.controlsNext.forEach( function( el ) { el.addEventListener( eventName, onNavigateNextClicked, false ); } ); |
4705 | + } ); |
4706 | + |
4707 | + } |
4708 | + |
4709 | + /** |
4710 | + * Unbinds all event listeners. |
4711 | + */ |
4712 | + function removeEventListeners() { |
4713 | + |
4714 | + eventsAreBound = false; |
4715 | + |
4716 | + document.removeEventListener( 'keydown', onDocumentKeyDown, false ); |
4717 | + document.removeEventListener( 'keypress', onDocumentKeyPress, false ); |
4718 | + window.removeEventListener( 'hashchange', onWindowHashChange, false ); |
4719 | + window.removeEventListener( 'resize', onWindowResize, false ); |
4720 | + |
4721 | + dom.wrapper.removeEventListener( 'pointerdown', onPointerDown, false ); |
4722 | + dom.wrapper.removeEventListener( 'pointermove', onPointerMove, false ); |
4723 | + dom.wrapper.removeEventListener( 'pointerup', onPointerUp, false ); |
4724 | + |
4725 | + dom.wrapper.removeEventListener( 'MSPointerDown', onPointerDown, false ); |
4726 | + dom.wrapper.removeEventListener( 'MSPointerMove', onPointerMove, false ); |
4727 | + dom.wrapper.removeEventListener( 'MSPointerUp', onPointerUp, false ); |
4728 | + |
4729 | + dom.wrapper.removeEventListener( 'touchstart', onTouchStart, false ); |
4730 | + dom.wrapper.removeEventListener( 'touchmove', onTouchMove, false ); |
4731 | + dom.wrapper.removeEventListener( 'touchend', onTouchEnd, false ); |
4732 | + |
4733 | + dom.resumeButton.removeEventListener( 'click', resume, false ); |
4734 | + |
4735 | + if ( config.progress && dom.progress ) { |
4736 | + dom.progress.removeEventListener( 'click', onProgressClicked, false ); |
4737 | + } |
4738 | + |
4739 | + [ 'touchstart', 'click' ].forEach( function( eventName ) { |
4740 | + dom.controlsLeft.forEach( function( el ) { el.removeEventListener( eventName, onNavigateLeftClicked, false ); } ); |
4741 | + dom.controlsRight.forEach( function( el ) { el.removeEventListener( eventName, onNavigateRightClicked, false ); } ); |
4742 | + dom.controlsUp.forEach( function( el ) { el.removeEventListener( eventName, onNavigateUpClicked, false ); } ); |
4743 | + dom.controlsDown.forEach( function( el ) { el.removeEventListener( eventName, onNavigateDownClicked, false ); } ); |
4744 | + dom.controlsPrev.forEach( function( el ) { el.removeEventListener( eventName, onNavigatePrevClicked, false ); } ); |
4745 | + dom.controlsNext.forEach( function( el ) { el.removeEventListener( eventName, onNavigateNextClicked, false ); } ); |
4746 | + } ); |
4747 | + |
4748 | + } |
4749 | + |
4750 | + /** |
4751 | + * Add a custom key binding with optional description to |
4752 | + * be added to the help screen. |
4753 | + */ |
4754 | + function addKeyBinding( binding, callback ) { |
4755 | + |
4756 | + if( typeof binding === 'object' && binding.keyCode ) { |
4757 | + registeredKeyBindings[binding.keyCode] = { |
4758 | + callback: callback, |
4759 | + key: binding.key, |
4760 | + description: binding.description |
4761 | + }; |
4762 | + } |
4763 | + else { |
4764 | + registeredKeyBindings[binding] = { |
4765 | + callback: callback, |
4766 | + key: null, |
4767 | + description: null |
4768 | + }; |
4769 | + } |
4770 | + |
4771 | + } |
4772 | + |
4773 | + /** |
4774 | + * Removes the specified custom key binding. |
4775 | + */ |
4776 | + function removeKeyBinding( keyCode ) { |
4777 | + |
4778 | + delete registeredKeyBindings[keyCode]; |
4779 | + |
4780 | + } |
4781 | + |
4782 | + /** |
4783 | + * Extend object a with the properties of object b. |
4784 | + * If there's a conflict, object b takes precedence. |
4785 | + * |
4786 | + * @param {object} a |
4787 | + * @param {object} b |
4788 | + */ |
4789 | + function extend( a, b ) { |
4790 | + |
4791 | + for( var i in b ) { |
4792 | + a[ i ] = b[ i ]; |
4793 | + } |
4794 | + |
4795 | + return a; |
4796 | + |
4797 | + } |
4798 | + |
4799 | + /** |
4800 | + * Converts the target object to an array. |
4801 | + * |
4802 | + * @param {object} o |
4803 | + * @return {object[]} |
4804 | + */ |
4805 | + function toArray( o ) { |
4806 | + |
4807 | + return Array.prototype.slice.call( o ); |
4808 | + |
4809 | + } |
4810 | + |
4811 | + /** |
4812 | + * Utility for deserializing a value. |
4813 | + * |
4814 | + * @param {*} value |
4815 | + * @return {*} |
4816 | + */ |
4817 | + function deserialize( value ) { |
4818 | + |
4819 | + if( typeof value === 'string' ) { |
4820 | + if( value === 'null' ) return null; |
4821 | + else if( value === 'true' ) return true; |
4822 | + else if( value === 'false' ) return false; |
4823 | + else if( value.match( /^-?[\d\.]+$/ ) ) return parseFloat( value ); |
4824 | + } |
4825 | + |
4826 | + return value; |
4827 | + |
4828 | + } |
4829 | + |
4830 | + /** |
4831 | + * Measures the distance in pixels between point a |
4832 | + * and point b. |
4833 | + * |
4834 | + * @param {object} a point with x/y properties |
4835 | + * @param {object} b point with x/y properties |
4836 | + * |
4837 | + * @return {number} |
4838 | + */ |
4839 | + function distanceBetween( a, b ) { |
4840 | + |
4841 | + var dx = a.x - b.x, |
4842 | + dy = a.y - b.y; |
4843 | + |
4844 | + return Math.sqrt( dx*dx + dy*dy ); |
4845 | + |
4846 | + } |
4847 | + |
4848 | + /** |
4849 | + * Applies a CSS transform to the target element. |
4850 | + * |
4851 | + * @param {HTMLElement} element |
4852 | + * @param {string} transform |
4853 | + */ |
4854 | + function transformElement( element, transform ) { |
4855 | + |
4856 | + element.style.WebkitTransform = transform; |
4857 | + element.style.MozTransform = transform; |
4858 | + element.style.msTransform = transform; |
4859 | + element.style.transform = transform; |
4860 | + |
4861 | + } |
4862 | + |
4863 | + /** |
4864 | + * Applies CSS transforms to the slides container. The container |
4865 | + * is transformed from two separate sources: layout and the overview |
4866 | + * mode. |
4867 | + * |
4868 | + * @param {object} transforms |
4869 | + */ |
4870 | + function transformSlides( transforms ) { |
4871 | + |
4872 | + // Pick up new transforms from arguments |
4873 | + if( typeof transforms.layout === 'string' ) slidesTransform.layout = transforms.layout; |
4874 | + if( typeof transforms.overview === 'string' ) slidesTransform.overview = transforms.overview; |
4875 | + |
4876 | + // Apply the transforms to the slides container |
4877 | + if( slidesTransform.layout ) { |
4878 | + transformElement( dom.slides, slidesTransform.layout + ' ' + slidesTransform.overview ); |
4879 | + } |
4880 | + else { |
4881 | + transformElement( dom.slides, slidesTransform.overview ); |
4882 | + } |
4883 | + |
4884 | + } |
4885 | + |
4886 | + /** |
4887 | + * Injects the given CSS styles into the DOM. |
4888 | + * |
4889 | + * @param {string} value |
4890 | + */ |
4891 | + function injectStyleSheet( value ) { |
4892 | + |
4893 | + var tag = document.createElement( 'style' ); |
4894 | + tag.type = 'text/css'; |
4895 | + if( tag.styleSheet ) { |
4896 | + tag.styleSheet.cssText = value; |
4897 | + } |
4898 | + else { |
4899 | + tag.appendChild( document.createTextNode( value ) ); |
4900 | + } |
4901 | + document.getElementsByTagName( 'head' )[0].appendChild( tag ); |
4902 | + |
4903 | + } |
4904 | + |
4905 | + /** |
4906 | + * Find the closest parent that matches the given |
4907 | + * selector. |
4908 | + * |
4909 | + * @param {HTMLElement} target The child element |
4910 | + * @param {String} selector The CSS selector to match |
4911 | + * the parents against |
4912 | + * |
4913 | + * @return {HTMLElement} The matched parent or null |
4914 | + * if no matching parent was found |
4915 | + */ |
4916 | + function closestParent( target, selector ) { |
4917 | + |
4918 | + var parent = target.parentNode; |
4919 | + |
4920 | + while( parent ) { |
4921 | + |
4922 | + // There's some overhead doing this each time, we don't |
4923 | + // want to rewrite the element prototype but should still |
4924 | + // be enough to feature detect once at startup... |
4925 | + var matchesMethod = parent.matches || parent.matchesSelector || parent.msMatchesSelector; |
4926 | + |
4927 | + // If we find a match, we're all set |
4928 | + if( matchesMethod && matchesMethod.call( parent, selector ) ) { |
4929 | + return parent; |
4930 | + } |
4931 | + |
4932 | + // Keep searching |
4933 | + parent = parent.parentNode; |
4934 | + |
4935 | + } |
4936 | + |
4937 | + return null; |
4938 | + |
4939 | + } |
4940 | + |
4941 | + /** |
4942 | + * Converts various color input formats to an {r:0,g:0,b:0} object. |
4943 | + * |
4944 | + * @param {string} color The string representation of a color |
4945 | + * @example |
4946 | + * colorToRgb('#000'); |
4947 | + * @example |
4948 | + * colorToRgb('#000000'); |
4949 | + * @example |
4950 | + * colorToRgb('rgb(0,0,0)'); |
4951 | + * @example |
4952 | + * colorToRgb('rgba(0,0,0)'); |
4953 | + * |
4954 | + * @return {{r: number, g: number, b: number, [a]: number}|null} |
4955 | + */ |
4956 | + function colorToRgb( color ) { |
4957 | + |
4958 | + var hex3 = color.match( /^#([0-9a-f]{3})$/i ); |
4959 | + if( hex3 && hex3[1] ) { |
4960 | + hex3 = hex3[1]; |
4961 | + return { |
4962 | + r: parseInt( hex3.charAt( 0 ), 16 ) * 0x11, |
4963 | + g: parseInt( hex3.charAt( 1 ), 16 ) * 0x11, |
4964 | + b: parseInt( hex3.charAt( 2 ), 16 ) * 0x11 |
4965 | + }; |
4966 | + } |
4967 | + |
4968 | + var hex6 = color.match( /^#([0-9a-f]{6})$/i ); |
4969 | + if( hex6 && hex6[1] ) { |
4970 | + hex6 = hex6[1]; |
4971 | + return { |
4972 | + r: parseInt( hex6.substr( 0, 2 ), 16 ), |
4973 | + g: parseInt( hex6.substr( 2, 2 ), 16 ), |
4974 | + b: parseInt( hex6.substr( 4, 2 ), 16 ) |
4975 | + }; |
4976 | + } |
4977 | + |
4978 | + var rgb = color.match( /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i ); |
4979 | + if( rgb ) { |
4980 | + return { |
4981 | + r: parseInt( rgb[1], 10 ), |
4982 | + g: parseInt( rgb[2], 10 ), |
4983 | + b: parseInt( rgb[3], 10 ) |
4984 | + }; |
4985 | + } |
4986 | + |
4987 | + var rgba = color.match( /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\,\s*([\d]+|[\d]*.[\d]+)\s*\)$/i ); |
4988 | + if( rgba ) { |
4989 | + return { |
4990 | + r: parseInt( rgba[1], 10 ), |
4991 | + g: parseInt( rgba[2], 10 ), |
4992 | + b: parseInt( rgba[3], 10 ), |
4993 | + a: parseFloat( rgba[4] ) |
4994 | + }; |
4995 | + } |
4996 | + |
4997 | + return null; |
4998 | + |
4999 | + } |
5000 | + |
The diff has been truncated for viewing.
Linux tests failed, please see https:/ /ci.openlp. io/job/ MP-02-Linux_ Tests/73/ for more details