phcthemes_admin_panel_pack 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/common/backstretch/jquery.backstretch.js +1602 -0
- data/app/assets/javascripts/common/bootstrap-datepicker/bootstrap-datepicker.js +2039 -0
- data/app/assets/javascripts/common/bootstrap-markdown/bootstrap-markdown.js +1390 -0
- data/app/assets/javascripts/common/bootstrap-select/bootstrap-select.js +3139 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-am_ET.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-am_ET.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-am_ET.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ar_AR.js +51 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ar_AR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ar_AR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-bg_BG.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-bg_BG.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-bg_BG.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-cs_CZ.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-cs_CZ.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-cs_CZ.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-da_DK.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-da_DK.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-da_DK.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-de_DE.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-de_DE.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-de_DE.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-en_US.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-en_US.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-en_US.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_CL.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_CL.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_CL.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_ES.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_ES.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_ES.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-et_EE.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-et_EE.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-et_EE.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-eu.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-eu.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-eu.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fa_IR.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fa_IR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fa_IR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fi_FI.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fi_FI.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fi_FI.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fr_FR.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fr_FR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fr_FR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hr_HR.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hr_HR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hr_HR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hu_HU.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hu_HU.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hu_HU.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-id_ID.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-id_ID.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-id_ID.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-it_IT.js +41 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-it_IT.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-it_IT.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ja_JP.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ja_JP.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ja_JP.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-kh_KM.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-kh_KM.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-kh_KM.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ko_KR.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ko_KR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ko_KR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lt_LT.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lt_LT.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lt_LT.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lv_LV.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lv_LV.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lv_LV.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nb_NO.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nb_NO.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nb_NO.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nl_NL.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nl_NL.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nl_NL.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pl_PL.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pl_PL.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pl_PL.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_BR.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_BR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_BR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_PT.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_PT.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_PT.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ro_RO.js +40 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ro_RO.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ro_RO.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ru_RU.js +40 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ru_RU.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ru_RU.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sk_SK.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sk_SK.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sk_SK.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sl_SI.js +44 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sl_SI.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sl_SI.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sv_SE.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sv_SE.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sv_SE.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-tr_TR.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-tr_TR.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-tr_TR.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ua_UA.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ua_UA.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ua_UA.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-vi_VN.js +46 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-vi_VN.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-vi_VN.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_CN.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_CN.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_CN.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_TW.js +39 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_TW.js.map +1 -0
- data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_TW.min.js +8 -0
- data/app/assets/javascripts/common/bootstrap/bootstrap.bundle.js +7013 -0
- data/app/assets/javascripts/common/bootstrap/bootstrap.three.js +2377 -0
- data/app/assets/javascripts/common/chartjs/chart.js +14680 -0
- data/app/assets/javascripts/common/custom/custom.js +0 -0
- data/app/assets/javascripts/common/datatables/datatables.js +15310 -0
- data/app/assets/javascripts/common/daterangepicker/daterangepicker.js +1565 -0
- data/app/assets/javascripts/common/fastclick/fastclick.js +841 -0
- data/app/assets/javascripts/common/flexslider/jquery.flexslider.js +1252 -0
- data/app/assets/javascripts/common/greenstock/greensock.js +36 -0
- data/app/assets/javascripts/common/icheck/icheck.js +509 -0
- data/app/assets/javascripts/common/imagesloaded/imagesloaded.pkgd.js +497 -0
- data/app/assets/javascripts/common/isotope/isotope.pkgd.js +3563 -0
- data/app/assets/javascripts/common/jquery-countdown/jquery.countdown.js +246 -0
- data/app/assets/javascripts/common/jquery-filterizer/jquery.filterizr.min.js +1 -0
- data/app/assets/javascripts/common/jquery-jvectormap/jquery-jvectormap.js +44 -0
- data/app/assets/javascripts/common/jquery-placeholder/jquery.placeholder.js +281 -0
- data/app/assets/javascripts/common/jquery-slimscroll/jquery.slimscroll.js +474 -0
- data/app/assets/javascripts/common/jquery-sparkline/jquery.sparkline.js +3054 -0
- data/app/assets/javascripts/common/jquery-ui/jquery-ui.js +18706 -0
- data/app/assets/javascripts/common/jquery-validation/jquery.validate.js +1650 -0
- data/app/assets/javascripts/common/jquery/jquery-3.4.1.js +10598 -0
- data/app/assets/javascripts/common/jqvmap/jquery.vmap.js +1281 -0
- data/app/assets/javascripts/common/jqvmap/jquery.vmap.min.js +10 -0
- data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.africa.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.asia.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.australia.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.europe.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.north-america.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.south-america.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.algeria.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.argentina.js +1 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.brazil.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.canada.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.europe.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.france.js +1 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.germany.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.greece.js +1 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.iran.js +6 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.iraq.js +1 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.russia.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.tunisia.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.turkey.js +11 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.usa.js +2 -0
- data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.world.js +2 -0
- data/app/assets/javascripts/common/js-cookie/js.cookie.js +165 -0
- data/app/assets/javascripts/common/layerslider/layerslider.kreaturamedia.jquery.js +13 -0
- data/app/assets/javascripts/common/layerslider/layerslider.origami.js +13 -0
- data/app/assets/javascripts/common/layerslider/layerslider.timeline.js +13 -0
- data/app/assets/javascripts/common/layerslider/layerslider.transitions.js +13 -0
- data/app/assets/javascripts/common/leaflet/leaflet.js +5 -0
- data/app/assets/javascripts/common/magnific-popup/jquery.magnific-popup.js +1860 -0
- data/app/assets/javascripts/common/mapbox/mapbox.js +51 -0
- data/app/assets/javascripts/common/metismenu/metisMenu.js +340 -0
- data/app/assets/javascripts/common/moderizer/modernizr.js +11 -0
- data/app/assets/javascripts/common/owl-carousel/owl.carousel.js +3448 -0
- data/app/assets/javascripts/common/pace/pace.js +935 -0
- data/app/assets/javascripts/common/paroller/jquery.paroller.js +228 -0
- data/app/assets/javascripts/common/particlejs/particles.js +1541 -0
- data/app/assets/javascripts/common/perfect-scrollbar/perfect-scrollbar.common.js +1318 -0
- data/app/assets/javascripts/common/perfect-scrollbar/perfect-scrollbar.esm.js +1316 -0
- data/app/assets/javascripts/common/perfect-scrollbar/perfect-scrollbar.js +1324 -0
- data/app/assets/javascripts/common/plyr/plyr.js +9137 -0
- data/app/assets/javascripts/common/rangeslider/rangeslider.js +498 -0
- data/app/assets/javascripts/common/retina/retina.js +100 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.actions.js +386 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.carousel.js +365 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.kenburn.js +199 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.layeranimation.js +2524 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.migration.js +260 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.navigation.js +1156 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.parallax.js +465 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.slideanims.js +1447 -0
- data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.video.js +1464 -0
- data/app/assets/javascripts/common/rev-slider/jquery.themepunch.revolution.js +3286 -0
- data/app/assets/javascripts/common/rev-slider/jquery.themepunch.tools.min.js +8710 -0
- data/app/assets/javascripts/common/scrollup/jquery.scrollUp.js +168 -0
- data/app/assets/javascripts/common/select2/select2.full.js +6597 -0
- data/app/assets/javascripts/common/selectbox/jquery.selectBox.js +1092 -0
- data/app/assets/javascripts/common/smooth-scroll/SmoothScroll.js +788 -0
- data/app/assets/javascripts/common/spectrum/spectrum.js +2323 -0
- data/app/assets/javascripts/common/stepper/jquery.fs.stepper.js +339 -0
- data/app/assets/javascripts/common/swiper/swiper.js +8124 -0
- data/app/assets/javascripts/common/toaster/toastr.js +476 -0
- data/app/assets/javascripts/common/typed/typed.js +1045 -0
- data/app/assets/javascripts/common/visable/jquery.visible.js +68 -0
- data/app/assets/javascripts/common/waypoints/jquery.waypoints.js +662 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_adminlte.js +12 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_basic.js +5 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_boomerang.js +0 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_coloradmin.js +10 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_inspinia.js +10 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_metronic.js +4 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_quilpro.js +5 -0
- data/app/assets/javascripts/phcthemes_admin_panel_pack_starlight.js +5 -0
- data/app/assets/javascripts/themes/adminlte/custom/custom.js +0 -0
- data/app/assets/javascripts/themes/adminlte/theme/adminlte.js +1141 -0
- data/app/assets/javascripts/themes/boomerang/custom/custom.1.js +0 -0
- data/app/assets/javascripts/themes/boomerang/custom/custom.js +0 -0
- data/app/assets/javascripts/themes/coloradmin/theme/apps.js +1650 -0
- data/app/assets/javascripts/themes/coloradmin/theme/default.js +152 -0
- data/app/assets/javascripts/themes/inspinia/custom/custom.js +0 -0
- data/app/assets/javascripts/themes/inspinia/theme/inspinia.js +279 -0
- data/app/assets/javascripts/themes/metronic/theme/scripts.bundle.js +9916 -0
- data/app/assets/javascripts/themes/metronic/theme/vendors.bundle.js +91352 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_adminlte.scss +13 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_basic.scss +6 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_boomerang.scss +24 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_coloradmin.scss +15 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_inspinia.scss +15 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_metronic.scss +7 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_quilpro.scss +16 -0
- data/app/assets/stylesheets/phcthemes_admin_panel_pack_starlight.scss +12 -0
- data/lib/phcthemes_admin_panel_pack/engine.rb +7 -5
- data/lib/phcthemes_admin_panel_pack/version.rb +1 -1
- metadata +234 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36ee242e4c8cb6c2991aefbdeb9ca75f809bf0f95f7c7e8226445887b25717f7
|
4
|
+
data.tar.gz: b9d80b4061d6674b36f1dd4d89a98e4e241c3826c23588349b137f48037aa0bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e77e1921b02d49a2716ac53cfe34d6104cc8cdb779d283c1e1420db203e7eebdf517c19a26f38f97c54bc81f3616305a3ff77c005c86c0313250f2f05dbf992f
|
7
|
+
data.tar.gz: dbd394dbe0d737c778acf1482c621a25b92364a398e33d138107edfaa3f04aa42169e565f92b3f15beb3ea706d132080a374437ebb285bd9ac976bdd189988f4
|
@@ -0,0 +1,1602 @@
|
|
1
|
+
/*
|
2
|
+
* Backstretch
|
3
|
+
* http://srobbin.com/jquery-plugins/backstretch/
|
4
|
+
*
|
5
|
+
* Copyright (c) 2013 Scott Robbin
|
6
|
+
* Licensed under the MIT license.
|
7
|
+
*/
|
8
|
+
|
9
|
+
;(function ($, window, undefined) {
|
10
|
+
'use strict';
|
11
|
+
|
12
|
+
/** @const */
|
13
|
+
var YOUTUBE_REGEXP = /^.*(youtu\.be\/|youtube\.com\/v\/|youtube\.com\/embed\/|youtube\.com\/watch\?v=|youtube\.com\/watch\?.*\&v=)([^#\&\?]*).*/i;
|
14
|
+
|
15
|
+
/* PLUGIN DEFINITION
|
16
|
+
* ========================= */
|
17
|
+
|
18
|
+
$.fn.backstretch = function (images, options) {
|
19
|
+
var args = arguments;
|
20
|
+
|
21
|
+
/*
|
22
|
+
* Scroll the page one pixel to get the right window height on iOS
|
23
|
+
* Pretty harmless for everyone else
|
24
|
+
*/
|
25
|
+
if ($(window).scrollTop() === 0) {
|
26
|
+
window.scrollTo(0, 0);
|
27
|
+
}
|
28
|
+
|
29
|
+
var returnValues;
|
30
|
+
|
31
|
+
this.each(function (eachIndex) {
|
32
|
+
var $this = $(this)
|
33
|
+
, obj = $this.data('backstretch');
|
34
|
+
|
35
|
+
// Do we already have an instance attached to this element?
|
36
|
+
if (obj) {
|
37
|
+
|
38
|
+
// Is this a method they're trying to execute?
|
39
|
+
if (typeof args[0] === 'string' &&
|
40
|
+
typeof obj[args[0]] === 'function') {
|
41
|
+
|
42
|
+
// Call the method
|
43
|
+
var returnValue = obj[args[0]].apply(obj, Array.prototype.slice.call(args, 1));
|
44
|
+
if (returnValue === obj) { // If a method is chaining
|
45
|
+
returnValue = undefined;
|
46
|
+
}
|
47
|
+
if (returnValue !== undefined) {
|
48
|
+
returnValues = returnValues || [];
|
49
|
+
returnValues[eachIndex] = returnValue;
|
50
|
+
}
|
51
|
+
|
52
|
+
return; // Nothing further to do
|
53
|
+
}
|
54
|
+
|
55
|
+
// Merge the old options with the new
|
56
|
+
options = $.extend(obj.options, options);
|
57
|
+
|
58
|
+
// Remove the old instance
|
59
|
+
if (typeof obj === 'object' && 'destroy' in obj) {
|
60
|
+
obj.destroy(true);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
// We need at least one image
|
65
|
+
if (!images || (images && images.length === 0)) {
|
66
|
+
var cssBackgroundImage = $this.css('background-image');
|
67
|
+
if (cssBackgroundImage && cssBackgroundImage !== 'none') {
|
68
|
+
images = [{url: $this.css('backgroundImage').replace(/url\(|\)|"|'/g, "")}];
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
$.error('No images were supplied for Backstretch, or element must have a CSS-defined background image.');
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
obj = new Backstretch(this, images, options || {});
|
76
|
+
$this.data('backstretch', obj);
|
77
|
+
});
|
78
|
+
|
79
|
+
return returnValues ? returnValues.length === 1 ? returnValues[0] : returnValues : this;
|
80
|
+
};
|
81
|
+
|
82
|
+
// If no element is supplied, we'll attach to body
|
83
|
+
$.backstretch = function (images, options) {
|
84
|
+
// Return the instance
|
85
|
+
return $('body')
|
86
|
+
.backstretch(images, options)
|
87
|
+
.data('backstretch');
|
88
|
+
};
|
89
|
+
|
90
|
+
// Custom selector
|
91
|
+
$.expr[':'].backstretch = function (elem) {
|
92
|
+
return $(elem).data('backstretch') !== undefined;
|
93
|
+
};
|
94
|
+
|
95
|
+
/* DEFAULTS
|
96
|
+
* ========================= */
|
97
|
+
|
98
|
+
$.fn.backstretch.defaults = {
|
99
|
+
duration: 5000 // Amount of time in between slides (if slideshow)
|
100
|
+
, transition: 'fade' // Type of transition between slides
|
101
|
+
, transitionDuration: 0 // Duration of transition between slides
|
102
|
+
, animateFirst: true // Animate the transition of first image of slideshow in?
|
103
|
+
, alignX: 0.5 // The x-alignment for the image, can be 'left'|'center'|'right' or any number between 0.0 and 1.0
|
104
|
+
, alignY: 0.5 // The y-alignment for the image, can be 'top'|'center'|'bottom' or any number between 0.0 and 1.0
|
105
|
+
, paused: false // Whether the images should slide after given duration
|
106
|
+
, start: 0 // Index of the first image to show
|
107
|
+
, preload: 2 // How many images preload at a time?
|
108
|
+
, preloadSize: 1 // How many images can we preload in parallel?
|
109
|
+
, resolutionRefreshRate: 2500 // How long to wait before switching resolution?
|
110
|
+
, resolutionChangeRatioThreshold: 0.1 // How much a change should it be before switching resolution?
|
111
|
+
};
|
112
|
+
|
113
|
+
/* STYLES
|
114
|
+
*
|
115
|
+
* Baked-in styles that we'll apply to our elements.
|
116
|
+
* In an effort to keep the plugin simple, these are not exposed as options.
|
117
|
+
* That said, anyone can override these in their own stylesheet.
|
118
|
+
* ========================= */
|
119
|
+
var styles = {
|
120
|
+
wrap: {
|
121
|
+
left: 0
|
122
|
+
, top: 0
|
123
|
+
, overflow: 'hidden'
|
124
|
+
, margin: 0
|
125
|
+
, padding: 0
|
126
|
+
, height: '100%'
|
127
|
+
, width: '100%'
|
128
|
+
, zIndex: -999999
|
129
|
+
}
|
130
|
+
, itemWrapper: {
|
131
|
+
position: 'absolute'
|
132
|
+
, display: 'none'
|
133
|
+
, margin: 0
|
134
|
+
, padding: 0
|
135
|
+
, border: 'none'
|
136
|
+
, width: '100%'
|
137
|
+
, height: '100%'
|
138
|
+
, zIndex: -999999
|
139
|
+
}
|
140
|
+
, item: {
|
141
|
+
position: 'absolute'
|
142
|
+
, margin: 0
|
143
|
+
, padding: 0
|
144
|
+
, border: 'none'
|
145
|
+
, width: '100%'
|
146
|
+
, height: '100%'
|
147
|
+
, maxWidth: 'none'
|
148
|
+
}
|
149
|
+
};
|
150
|
+
|
151
|
+
/* Given an array of different options for an image,
|
152
|
+
* choose the optimal image for the container size.
|
153
|
+
*
|
154
|
+
* Given an image template (a string with {{ width }} and/or
|
155
|
+
* {{height}} inside) and a container object, returns the
|
156
|
+
* image url with the exact values for the size of that
|
157
|
+
* container.
|
158
|
+
*
|
159
|
+
* Returns an array of urls optimized for the specified resolution.
|
160
|
+
*
|
161
|
+
*/
|
162
|
+
var optimalSizeImages = (function () {
|
163
|
+
|
164
|
+
/* Sorts the array of image sizes based on width */
|
165
|
+
var widthInsertSort = function (arr) {
|
166
|
+
for (var i = 1; i < arr.length; i++) {
|
167
|
+
var tmp = arr[i],
|
168
|
+
j = i;
|
169
|
+
while (arr[j - 1] && parseInt(arr[j - 1].width, 10) > parseInt(tmp.width, 10)) {
|
170
|
+
arr[j] = arr[j - 1];
|
171
|
+
--j;
|
172
|
+
}
|
173
|
+
arr[j] = tmp;
|
174
|
+
}
|
175
|
+
|
176
|
+
return arr;
|
177
|
+
};
|
178
|
+
|
179
|
+
/* Given an array of various sizes of the same image and a container width,
|
180
|
+
* return the best image.
|
181
|
+
*/
|
182
|
+
var selectBest = function (containerWidth, containerHeight, imageSizes) {
|
183
|
+
|
184
|
+
var devicePixelRatio = window.devicePixelRatio || 1;
|
185
|
+
var deviceOrientation = getDeviceOrientation();
|
186
|
+
var windowOrientation = getWindowOrientation();
|
187
|
+
var wrapperOrientation = (containerHeight > containerWidth) ?
|
188
|
+
'portrait' :
|
189
|
+
(containerWidth > containerHeight ? 'landscape' : 'square');
|
190
|
+
|
191
|
+
var lastAllowedImage = 0;
|
192
|
+
var testWidth;
|
193
|
+
|
194
|
+
for (var j = 0, image; j < imageSizes.length; j++) {
|
195
|
+
|
196
|
+
image = imageSizes[j];
|
197
|
+
|
198
|
+
// In case a new image was pushed in, process it:
|
199
|
+
if (typeof image === 'string') {
|
200
|
+
image = imageSizes[j] = {url: image};
|
201
|
+
}
|
202
|
+
|
203
|
+
if (image.pixelRatio && image.pixelRatio !== 'auto' && parseFloat(image.pixelRatio) !== devicePixelRatio) {
|
204
|
+
// We disallowed choosing this image for current device pixel ratio,
|
205
|
+
// So skip this one.
|
206
|
+
continue;
|
207
|
+
}
|
208
|
+
|
209
|
+
if (image.deviceOrientation && image.deviceOrientation !== deviceOrientation) {
|
210
|
+
// We disallowed choosing this image for current device orientation,
|
211
|
+
// So skip this one.
|
212
|
+
continue;
|
213
|
+
}
|
214
|
+
|
215
|
+
if (image.windowOrientation && image.windowOrientation !== deviceOrientation) {
|
216
|
+
// We disallowed choosing this image for current window orientation,
|
217
|
+
// So skip this one.
|
218
|
+
continue;
|
219
|
+
}
|
220
|
+
|
221
|
+
if (image.orientation && image.orientation !== wrapperOrientation) {
|
222
|
+
// We disallowed choosing this image for current element's orientation,
|
223
|
+
// So skip this one.
|
224
|
+
continue;
|
225
|
+
}
|
226
|
+
|
227
|
+
// Mark this one as the last one we investigated
|
228
|
+
// which does not violate device pixel ratio rules.
|
229
|
+
// We may choose this one later if there's no match.
|
230
|
+
lastAllowedImage = j;
|
231
|
+
|
232
|
+
// For most images, we match the specified width against element width,
|
233
|
+
// And enforcing a limit depending on the "pixelRatio" property if specified.
|
234
|
+
// But if a pixelRatio="auto", then we consider the width as the physical width of the image,
|
235
|
+
// And match it while considering the device's pixel ratio.
|
236
|
+
testWidth = containerWidth;
|
237
|
+
if (image.pixelRatio === 'auto') {
|
238
|
+
containerWidth *= devicePixelRatio;
|
239
|
+
}
|
240
|
+
|
241
|
+
// Stop when the width of the image is larger or equal to the container width
|
242
|
+
if (image.width >= testWidth) {
|
243
|
+
break;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
// Use the image located at where we stopped
|
248
|
+
return imageSizes[Math.min(j, lastAllowedImage)];
|
249
|
+
};
|
250
|
+
|
251
|
+
var replaceTagsInUrl = function (url, templateReplacer) {
|
252
|
+
|
253
|
+
if (typeof url === 'string') {
|
254
|
+
url = url.replace(/{{(width|height)}}/g, templateReplacer);
|
255
|
+
}
|
256
|
+
else if (url instanceof Array) {
|
257
|
+
for (var i = 0; i < url.length; i++) {
|
258
|
+
if (url[i].src) {
|
259
|
+
url[i].src = replaceTagsInUrl(url[i].src, templateReplacer);
|
260
|
+
}
|
261
|
+
else {
|
262
|
+
url[i] = replaceTagsInUrl(url[i], templateReplacer);
|
263
|
+
}
|
264
|
+
}
|
265
|
+
}
|
266
|
+
|
267
|
+
return url;
|
268
|
+
};
|
269
|
+
|
270
|
+
return function ($container, images) {
|
271
|
+
var containerWidth = $container.width(),
|
272
|
+
containerHeight = $container.height();
|
273
|
+
|
274
|
+
var chosenImages = [];
|
275
|
+
|
276
|
+
var templateReplacer = function (match, key) {
|
277
|
+
if (key === 'width') {
|
278
|
+
return containerWidth;
|
279
|
+
}
|
280
|
+
if (key === 'height') {
|
281
|
+
return containerHeight;
|
282
|
+
}
|
283
|
+
return match;
|
284
|
+
};
|
285
|
+
|
286
|
+
for (var i = 0; i < images.length; i++) {
|
287
|
+
if ($.isArray(images[i])) {
|
288
|
+
images[i] = widthInsertSort(images[i]);
|
289
|
+
var chosen = selectBest(containerWidth, containerHeight, images[i]);
|
290
|
+
chosenImages.push(chosen);
|
291
|
+
}
|
292
|
+
else {
|
293
|
+
// In case a new image was pushed in, process it:
|
294
|
+
if (typeof images[i] === 'string') {
|
295
|
+
images[i] = {url: images[i]};
|
296
|
+
}
|
297
|
+
|
298
|
+
var item = $.extend({}, images[i]);
|
299
|
+
item.url = replaceTagsInUrl(item.url, templateReplacer);
|
300
|
+
chosenImages.push(item);
|
301
|
+
}
|
302
|
+
}
|
303
|
+
return chosenImages;
|
304
|
+
};
|
305
|
+
|
306
|
+
})();
|
307
|
+
|
308
|
+
var isVideoSource = function (source) {
|
309
|
+
return YOUTUBE_REGEXP.test(source.url) || source.isVideo;
|
310
|
+
};
|
311
|
+
|
312
|
+
/* Preload images */
|
313
|
+
var preload = (function (sources, startAt, count, batchSize, callback) {
|
314
|
+
// Plugin cache
|
315
|
+
var cache = [];
|
316
|
+
|
317
|
+
// Wrapper for cache
|
318
|
+
var caching = function (image) {
|
319
|
+
for (var i = 0; i < cache.length; i++) {
|
320
|
+
if (cache[i].src === image.src) {
|
321
|
+
return cache[i];
|
322
|
+
}
|
323
|
+
}
|
324
|
+
cache.push(image);
|
325
|
+
return image;
|
326
|
+
};
|
327
|
+
|
328
|
+
// Execute callback
|
329
|
+
var exec = function (sources, callback, last) {
|
330
|
+
if (typeof callback === 'function') {
|
331
|
+
callback.call(sources, last);
|
332
|
+
}
|
333
|
+
};
|
334
|
+
|
335
|
+
// Closure to hide cache
|
336
|
+
return function preload(sources, startAt, count, batchSize, callback) {
|
337
|
+
// Check input data
|
338
|
+
if (typeof sources === 'undefined') {
|
339
|
+
return;
|
340
|
+
}
|
341
|
+
if (!$.isArray(sources)) {
|
342
|
+
sources = [sources];
|
343
|
+
}
|
344
|
+
|
345
|
+
if (arguments.length < 5 && typeof arguments[arguments.length - 1] === 'function') {
|
346
|
+
callback = arguments[arguments.length - 1];
|
347
|
+
}
|
348
|
+
|
349
|
+
startAt = (typeof startAt === 'function' || !startAt) ? 0 : startAt;
|
350
|
+
count = (typeof count === 'function' || !count || count < 0) ? sources.length : Math.min(count, sources.length);
|
351
|
+
batchSize = (typeof batchSize === 'function' || !batchSize) ? 1 : batchSize;
|
352
|
+
|
353
|
+
if (startAt >= sources.length) {
|
354
|
+
startAt = 0;
|
355
|
+
count = 0;
|
356
|
+
}
|
357
|
+
if (batchSize < 0) {
|
358
|
+
batchSize = count;
|
359
|
+
}
|
360
|
+
batchSize = Math.min(batchSize, count);
|
361
|
+
|
362
|
+
var next = sources.slice(startAt + batchSize, count - batchSize);
|
363
|
+
sources = sources.slice(startAt, batchSize);
|
364
|
+
count = sources.length;
|
365
|
+
|
366
|
+
// If sources array is empty
|
367
|
+
if (!count) {
|
368
|
+
exec(sources, callback, true);
|
369
|
+
return;
|
370
|
+
}
|
371
|
+
|
372
|
+
// Image loading callback
|
373
|
+
var countLoaded = 0;
|
374
|
+
|
375
|
+
var loaded = function () {
|
376
|
+
countLoaded++;
|
377
|
+
if (countLoaded !== count) {
|
378
|
+
return;
|
379
|
+
}
|
380
|
+
|
381
|
+
exec(sources, callback, !next);
|
382
|
+
preload(next, 0, 0, batchSize, callback);
|
383
|
+
};
|
384
|
+
|
385
|
+
// Loop sources to preload
|
386
|
+
var image;
|
387
|
+
|
388
|
+
for (var i = 0; i < sources.length; i++) {
|
389
|
+
|
390
|
+
if (isVideoSource(sources[i])) {
|
391
|
+
|
392
|
+
// Do not preload videos. There are issues with that.
|
393
|
+
// First - we need to keep an instance of the preloaded and use that exactly, not a copy.
|
394
|
+
// Second - there are memory issues.
|
395
|
+
// If there will be a requirement from users - I'll try to implement this.
|
396
|
+
|
397
|
+
continue;
|
398
|
+
|
399
|
+
}
|
400
|
+
else {
|
401
|
+
|
402
|
+
image = new Image();
|
403
|
+
image.src = sources[i].url;
|
404
|
+
|
405
|
+
image = caching(image);
|
406
|
+
|
407
|
+
if (image.complete) {
|
408
|
+
loaded();
|
409
|
+
}
|
410
|
+
else {
|
411
|
+
$(image).on('load error', loaded);
|
412
|
+
}
|
413
|
+
|
414
|
+
}
|
415
|
+
|
416
|
+
}
|
417
|
+
};
|
418
|
+
})();
|
419
|
+
|
420
|
+
/* Process images array */
|
421
|
+
var processImagesArray = function (images) {
|
422
|
+
var processed = [];
|
423
|
+
for (var i = 0; i < images.length; i++) {
|
424
|
+
if (typeof images[i] === 'string') {
|
425
|
+
processed.push({url: images[i]});
|
426
|
+
}
|
427
|
+
else if ($.isArray(images[i])) {
|
428
|
+
processed.push(processImagesArray(images[i]));
|
429
|
+
}
|
430
|
+
else {
|
431
|
+
processed.push(processOptions(images[i]));
|
432
|
+
}
|
433
|
+
}
|
434
|
+
return processed;
|
435
|
+
};
|
436
|
+
|
437
|
+
/* Process options */
|
438
|
+
var processOptions = function (options, required) {
|
439
|
+
|
440
|
+
// Convert old options
|
441
|
+
|
442
|
+
// centeredX/centeredY are deprecated
|
443
|
+
if (options.centeredX || options.centeredY) {
|
444
|
+
if (window.console && window.console.log) {
|
445
|
+
window.console.log('jquery.backstretch: `centeredX`/`centeredY` is deprecated, please use `alignX`/`alignY`');
|
446
|
+
}
|
447
|
+
if (options.centeredX) {
|
448
|
+
options.alignX = 0.5;
|
449
|
+
}
|
450
|
+
if (options.centeredY) {
|
451
|
+
options.alignY = 0.5;
|
452
|
+
}
|
453
|
+
}
|
454
|
+
|
455
|
+
// Deprecated spec
|
456
|
+
if (options.speed !== undefined) {
|
457
|
+
|
458
|
+
if (window.console && window.console.log) {
|
459
|
+
window.console.log('jquery.backstretch: `speed` is deprecated, please use `transitionDuration`');
|
460
|
+
}
|
461
|
+
|
462
|
+
options.transitionDuration = options.speed;
|
463
|
+
options.transition = 'fade';
|
464
|
+
}
|
465
|
+
|
466
|
+
// Typo
|
467
|
+
if (options.resolutionChangeRatioTreshold !== undefined) {
|
468
|
+
window.console.log('jquery.backstretch: `treshold` is a typo!');
|
469
|
+
options.resolutionChangeRatioThreshold = options.resolutionChangeRatioTreshold;
|
470
|
+
}
|
471
|
+
|
472
|
+
// Current spec that needs processing
|
473
|
+
|
474
|
+
if (options.fadeFirst !== undefined) {
|
475
|
+
options.animateFirst = options.fadeFirst;
|
476
|
+
}
|
477
|
+
|
478
|
+
if (options.fade !== undefined) {
|
479
|
+
options.transitionDuration = options.fade;
|
480
|
+
options.transition = 'fade';
|
481
|
+
}
|
482
|
+
|
483
|
+
if (options.scale) {
|
484
|
+
options.scale = validScale(options.scale);
|
485
|
+
}
|
486
|
+
|
487
|
+
return processAlignOptions(options);
|
488
|
+
};
|
489
|
+
|
490
|
+
/* Process align options */
|
491
|
+
var processAlignOptions = function (options, required) {
|
492
|
+
if (options.alignX === 'left') {
|
493
|
+
options.alignX = 0.0;
|
494
|
+
}
|
495
|
+
else if (options.alignX === 'center') {
|
496
|
+
options.alignX = 0.5;
|
497
|
+
}
|
498
|
+
else if (options.alignX === 'right') {
|
499
|
+
options.alignX = 1.0;
|
500
|
+
}
|
501
|
+
else {
|
502
|
+
if (options.alignX !== undefined || required) {
|
503
|
+
options.alignX = parseFloat(options.alignX);
|
504
|
+
if (isNaN(options.alignX)) {
|
505
|
+
options.alignX = 0.5;
|
506
|
+
}
|
507
|
+
}
|
508
|
+
}
|
509
|
+
|
510
|
+
if (options.alignY === 'top') {
|
511
|
+
options.alignY = 0.0;
|
512
|
+
}
|
513
|
+
else if (options.alignY === 'center') {
|
514
|
+
options.alignY = 0.5;
|
515
|
+
}
|
516
|
+
else if (options.alignY === 'bottom') {
|
517
|
+
options.alignY = 1.0;
|
518
|
+
}
|
519
|
+
else {
|
520
|
+
if (options.alignX !== undefined || required) {
|
521
|
+
options.alignY = parseFloat(options.alignY);
|
522
|
+
if (isNaN(options.alignY)) {
|
523
|
+
options.alignY = 0.5;
|
524
|
+
}
|
525
|
+
}
|
526
|
+
}
|
527
|
+
|
528
|
+
return options;
|
529
|
+
};
|
530
|
+
|
531
|
+
var SUPPORTED_SCALE_OPTIONS = {
|
532
|
+
'cover': 'cover',
|
533
|
+
'fit': 'fit',
|
534
|
+
'fit-smaller': 'fit-smaller',
|
535
|
+
'fill': 'fill'
|
536
|
+
};
|
537
|
+
|
538
|
+
function validScale(scale) {
|
539
|
+
if (!SUPPORTED_SCALE_OPTIONS.hasOwnProperty(scale)) {
|
540
|
+
return 'cover';
|
541
|
+
}
|
542
|
+
return scale;
|
543
|
+
}
|
544
|
+
|
545
|
+
/* CLASS DEFINITION
|
546
|
+
* ========================= */
|
547
|
+
var Backstretch = function (container, images, options) {
|
548
|
+
this.options = $.extend({}, $.fn.backstretch.defaults, options || {});
|
549
|
+
|
550
|
+
this.firstShow = true;
|
551
|
+
|
552
|
+
// Process options
|
553
|
+
processOptions(this.options, true);
|
554
|
+
|
555
|
+
/* In its simplest form, we allow Backstretch to be called on an image path.
|
556
|
+
* e.g. $.backstretch('/path/to/image.jpg')
|
557
|
+
* So, we need to turn this back into an array.
|
558
|
+
*/
|
559
|
+
this.images = processImagesArray($.isArray(images) ? images : [images]);
|
560
|
+
|
561
|
+
/**
|
562
|
+
* Paused-Option
|
563
|
+
*/
|
564
|
+
if (this.options.paused) {
|
565
|
+
this.paused = true;
|
566
|
+
}
|
567
|
+
|
568
|
+
/**
|
569
|
+
* Start-Option (Index)
|
570
|
+
*/
|
571
|
+
if (this.options.start >= this.images.length) {
|
572
|
+
this.options.start = this.images.length - 1;
|
573
|
+
}
|
574
|
+
if (this.options.start < 0) {
|
575
|
+
this.options.start = 0;
|
576
|
+
}
|
577
|
+
|
578
|
+
// Convenience reference to know if the container is body.
|
579
|
+
this.isBody = container === document.body;
|
580
|
+
|
581
|
+
/* We're keeping track of a few different elements
|
582
|
+
*
|
583
|
+
* Container: the element that Backstretch was called on.
|
584
|
+
* Wrap: a DIV that we place the image into, so we can hide the overflow.
|
585
|
+
* Root: Convenience reference to help calculate the correct height.
|
586
|
+
*/
|
587
|
+
var $window = $(window);
|
588
|
+
this.$container = $(container);
|
589
|
+
this.$root = this.isBody ? supportsFixedPosition ? $window : $(document) : this.$container;
|
590
|
+
|
591
|
+
this.originalImages = this.images;
|
592
|
+
this.images = optimalSizeImages(
|
593
|
+
this.options.alwaysTestWindowResolution ? $window : this.$root,
|
594
|
+
this.originalImages);
|
595
|
+
|
596
|
+
/**
|
597
|
+
* Pre-Loading.
|
598
|
+
* This is the first image, so we will preload a minimum of 1 images.
|
599
|
+
*/
|
600
|
+
preload(this.images, this.options.start || 0, this.options.preload || 1);
|
601
|
+
|
602
|
+
// Don't create a new wrap if one already exists (from a previous instance of Backstretch)
|
603
|
+
var $existing = this.$container.children(".backstretch").first();
|
604
|
+
this.$wrap = $existing.length ? $existing :
|
605
|
+
$('<div class="backstretch"></div>')
|
606
|
+
.css(this.options.bypassCss ? {} : styles.wrap)
|
607
|
+
.appendTo(this.$container);
|
608
|
+
|
609
|
+
if (!this.options.bypassCss) {
|
610
|
+
|
611
|
+
// Non-body elements need some style adjustments
|
612
|
+
if (!this.isBody) {
|
613
|
+
// If the container is statically positioned, we need to make it relative,
|
614
|
+
// and if no zIndex is defined, we should set it to zero.
|
615
|
+
var position = this.$container.css('position')
|
616
|
+
, zIndex = this.$container.css('zIndex');
|
617
|
+
|
618
|
+
this.$container.css({
|
619
|
+
position: position === 'static' ? 'relative' : position
|
620
|
+
, zIndex: zIndex === 'auto' ? 0 : zIndex
|
621
|
+
});
|
622
|
+
|
623
|
+
// Needs a higher z-index
|
624
|
+
this.$wrap.css({zIndex: -999998});
|
625
|
+
}
|
626
|
+
|
627
|
+
// Fixed or absolute positioning?
|
628
|
+
this.$wrap.css({
|
629
|
+
position: this.isBody && supportsFixedPosition ? 'fixed' : 'absolute'
|
630
|
+
});
|
631
|
+
|
632
|
+
}
|
633
|
+
|
634
|
+
// Set the first image
|
635
|
+
this.index = this.options.start;
|
636
|
+
this.show(this.index);
|
637
|
+
|
638
|
+
// Listen for resize
|
639
|
+
$window.on('resize.backstretch', $.proxy(this.resize, this))
|
640
|
+
.on('orientationchange.backstretch', $.proxy(function () {
|
641
|
+
// Need to do this in order to get the right window height
|
642
|
+
if (this.isBody && window.pageYOffset === 0) {
|
643
|
+
window.scrollTo(0, 1);
|
644
|
+
this.resize();
|
645
|
+
}
|
646
|
+
}, this));
|
647
|
+
};
|
648
|
+
|
649
|
+
var performTransition = function (options) {
|
650
|
+
|
651
|
+
var transition = options.transition || 'fade';
|
652
|
+
|
653
|
+
// Look for multiple options
|
654
|
+
if (typeof transition === 'string' && transition.indexOf('|') > -1) {
|
655
|
+
transition = transition.split('|');
|
656
|
+
}
|
657
|
+
|
658
|
+
if (transition instanceof Array) {
|
659
|
+
transition = transition[Math.round(Math.random() * (transition.length - 1))];
|
660
|
+
}
|
661
|
+
|
662
|
+
var $new = options['new'];
|
663
|
+
var $old = options['old'] ? options['old'] : $([]);
|
664
|
+
|
665
|
+
switch (transition.toString().toLowerCase()) {
|
666
|
+
|
667
|
+
default:
|
668
|
+
case 'fade':
|
669
|
+
$new.fadeIn({
|
670
|
+
duration: options.duration,
|
671
|
+
complete: options.complete,
|
672
|
+
easing: options.easing || undefined
|
673
|
+
});
|
674
|
+
break;
|
675
|
+
|
676
|
+
case 'fadeinout':
|
677
|
+
case 'fade_in_out':
|
678
|
+
|
679
|
+
var fadeInNew = function () {
|
680
|
+
$new.fadeIn({
|
681
|
+
duration: options.duration / 2,
|
682
|
+
complete: options.complete,
|
683
|
+
easing: options.easing || undefined
|
684
|
+
});
|
685
|
+
};
|
686
|
+
|
687
|
+
if ($old.length) {
|
688
|
+
$old.fadeOut({
|
689
|
+
duration: options.duration / 2,
|
690
|
+
complete: fadeInNew,
|
691
|
+
easing: options.easing || undefined
|
692
|
+
});
|
693
|
+
}
|
694
|
+
else {
|
695
|
+
fadeInNew();
|
696
|
+
}
|
697
|
+
|
698
|
+
break;
|
699
|
+
|
700
|
+
case 'pushleft':
|
701
|
+
case 'push_left':
|
702
|
+
case 'pushright':
|
703
|
+
case 'push_right':
|
704
|
+
case 'pushup':
|
705
|
+
case 'push_up':
|
706
|
+
case 'pushdown':
|
707
|
+
case 'push_down':
|
708
|
+
case 'coverleft':
|
709
|
+
case 'cover_left':
|
710
|
+
case 'coverright':
|
711
|
+
case 'cover_right':
|
712
|
+
case 'coverup':
|
713
|
+
case 'cover_up':
|
714
|
+
case 'coverdown':
|
715
|
+
case 'cover_down':
|
716
|
+
|
717
|
+
var transitionParts = transition.match(/^(cover|push)_?(.*)$/);
|
718
|
+
|
719
|
+
var animProp = transitionParts[2] === 'left' ? 'right' :
|
720
|
+
transitionParts[2] === 'right' ? 'left' :
|
721
|
+
transitionParts[2] === 'down' ? 'top' :
|
722
|
+
transitionParts[2] === 'up' ? 'bottom' :
|
723
|
+
'right';
|
724
|
+
|
725
|
+
var newCssStart = {
|
726
|
+
'display': ''
|
727
|
+
}, newCssAnim = {};
|
728
|
+
newCssStart[animProp] = '-100%';
|
729
|
+
newCssAnim[animProp] = 0;
|
730
|
+
|
731
|
+
$new
|
732
|
+
.css(newCssStart)
|
733
|
+
.animate(newCssAnim, {
|
734
|
+
duration: options.duration,
|
735
|
+
complete: function () {
|
736
|
+
$new.css(animProp, '');
|
737
|
+
options.complete.apply(this, arguments);
|
738
|
+
},
|
739
|
+
easing: options.easing || undefined
|
740
|
+
});
|
741
|
+
|
742
|
+
if (transitionParts[1] === 'push' && $old.length) {
|
743
|
+
var oldCssAnim = {};
|
744
|
+
oldCssAnim[animProp] = '100%';
|
745
|
+
|
746
|
+
$old
|
747
|
+
.animate(oldCssAnim, {
|
748
|
+
duration: options.duration,
|
749
|
+
complete: function () {
|
750
|
+
$old.css('display', 'none');
|
751
|
+
},
|
752
|
+
easing: options.easing || undefined
|
753
|
+
});
|
754
|
+
}
|
755
|
+
|
756
|
+
break;
|
757
|
+
}
|
758
|
+
|
759
|
+
};
|
760
|
+
|
761
|
+
/* PUBLIC METHODS
|
762
|
+
* ========================= */
|
763
|
+
Backstretch.prototype = {
|
764
|
+
|
765
|
+
resize: function () {
|
766
|
+
try {
|
767
|
+
|
768
|
+
// Check for a better suited image after the resize
|
769
|
+
var $resTest = this.options.alwaysTestWindowResolution ? $(window) : this.$root;
|
770
|
+
var newContainerWidth = $resTest.width();
|
771
|
+
var newContainerHeight = $resTest.height();
|
772
|
+
var changeRatioW = newContainerWidth / (this._lastResizeContainerWidth || 0);
|
773
|
+
var changeRatioH = newContainerHeight / (this._lastResizeContainerHeight || 0);
|
774
|
+
var resolutionChangeRatioThreshold = this.options.resolutionChangeRatioThreshold || 0.0;
|
775
|
+
|
776
|
+
// check for big changes in container size
|
777
|
+
if ((newContainerWidth !== this._lastResizeContainerWidth ||
|
778
|
+
newContainerHeight !== this._lastResizeContainerHeight) &&
|
779
|
+
((Math.abs(changeRatioW - 1) >= resolutionChangeRatioThreshold || isNaN(changeRatioW)) ||
|
780
|
+
(Math.abs(changeRatioH - 1) >= resolutionChangeRatioThreshold || isNaN(changeRatioH)))) {
|
781
|
+
|
782
|
+
this._lastResizeContainerWidth = newContainerWidth;
|
783
|
+
this._lastResizeContainerHeight = newContainerHeight;
|
784
|
+
|
785
|
+
// Big change: rebuild the entire images array
|
786
|
+
this.images = optimalSizeImages($resTest, this.originalImages);
|
787
|
+
|
788
|
+
// Preload them (they will be automatically inserted on the next cycle)
|
789
|
+
if (this.options.preload) {
|
790
|
+
preload(this.images, (this.index + 1) % this.images.length, this.options.preload);
|
791
|
+
}
|
792
|
+
|
793
|
+
// In case there is no cycle and the new source is different than the current
|
794
|
+
if (this.images.length === 1 &&
|
795
|
+
this._currentImage.url !== this.images[0].url) {
|
796
|
+
|
797
|
+
// Wait a little an update the image being showed
|
798
|
+
var that = this;
|
799
|
+
clearTimeout(that._selectAnotherResolutionTimeout);
|
800
|
+
that._selectAnotherResolutionTimeout = setTimeout(function () {
|
801
|
+
that.show(0);
|
802
|
+
}, this.options.resolutionRefreshRate);
|
803
|
+
}
|
804
|
+
}
|
805
|
+
|
806
|
+
var bgCSS = {left: 0, top: 0, right: 'auto', bottom: 'auto'}
|
807
|
+
|
808
|
+
, boxWidth = this.isBody ? this.$root.width() : this.$root.innerWidth()
|
809
|
+
, boxHeight = this.isBody
|
810
|
+
? (window.innerHeight ? window.innerHeight : this.$root.height())
|
811
|
+
: this.$root.innerHeight()
|
812
|
+
|
813
|
+
, naturalWidth = this.$itemWrapper.data('width')
|
814
|
+
, naturalHeight = this.$itemWrapper.data('height')
|
815
|
+
|
816
|
+
, ratio = (naturalWidth / naturalHeight) || 1
|
817
|
+
|
818
|
+
, alignX = this._currentImage.alignX === undefined ? this.options.alignX : this._currentImage.alignX
|
819
|
+
, alignY = this._currentImage.alignY === undefined ? this.options.alignY : this._currentImage.alignY
|
820
|
+
, scale = validScale(this._currentImage.scale || this.options.scale);
|
821
|
+
|
822
|
+
var width, height;
|
823
|
+
|
824
|
+
if (scale === 'fit' || scale === 'fit-smaller') {
|
825
|
+
width = naturalWidth;
|
826
|
+
height = naturalHeight;
|
827
|
+
|
828
|
+
if (width > boxWidth ||
|
829
|
+
height > boxHeight ||
|
830
|
+
scale === 'fit-smaller') {
|
831
|
+
var boxRatio = boxWidth / boxHeight;
|
832
|
+
if (boxRatio > ratio) {
|
833
|
+
width = Math.floor(boxHeight * ratio);
|
834
|
+
height = boxHeight;
|
835
|
+
}
|
836
|
+
else if (boxRatio < ratio) {
|
837
|
+
width = boxWidth;
|
838
|
+
height = Math.floor(boxWidth / ratio);
|
839
|
+
}
|
840
|
+
else {
|
841
|
+
width = boxWidth;
|
842
|
+
height = boxHeight;
|
843
|
+
}
|
844
|
+
}
|
845
|
+
}
|
846
|
+
else if (scale === 'fill') {
|
847
|
+
width = boxWidth;
|
848
|
+
height = boxHeight;
|
849
|
+
}
|
850
|
+
else { // 'cover'
|
851
|
+
width = Math.max(boxHeight * ratio, boxWidth);
|
852
|
+
height = Math.max(width / ratio, boxHeight);
|
853
|
+
}
|
854
|
+
|
855
|
+
// Make adjustments based on image ratio
|
856
|
+
bgCSS.top = -(height - boxHeight) * alignY;
|
857
|
+
bgCSS.left = -(width - boxWidth) * alignX;
|
858
|
+
bgCSS.width = width;
|
859
|
+
bgCSS.height = height;
|
860
|
+
|
861
|
+
if (!this.options.bypassCss) {
|
862
|
+
|
863
|
+
this.$wrap
|
864
|
+
.css({width: boxWidth, height: boxHeight})
|
865
|
+
.find('>.backstretch-item').not('.deleteable')
|
866
|
+
.each(function () {
|
867
|
+
var $wrapper = $(this);
|
868
|
+
$wrapper.find('img,video,iframe')
|
869
|
+
.css(bgCSS);
|
870
|
+
});
|
871
|
+
}
|
872
|
+
|
873
|
+
var evt = $.Event('backstretch.resize', {
|
874
|
+
relatedTarget: this.$container[0]
|
875
|
+
});
|
876
|
+
this.$container.trigger(evt, this);
|
877
|
+
|
878
|
+
}
|
879
|
+
catch (err) {
|
880
|
+
// IE7 seems to trigger resize before the image is loaded.
|
881
|
+
// This try/catch block is a hack to let it fail gracefully.
|
882
|
+
}
|
883
|
+
|
884
|
+
return this;
|
885
|
+
}
|
886
|
+
|
887
|
+
// Show the slide at a certain position
|
888
|
+
, show: function (newIndex, overrideOptions) {
|
889
|
+
|
890
|
+
// Validate index
|
891
|
+
if (Math.abs(newIndex) > this.images.length - 1) {
|
892
|
+
return;
|
893
|
+
}
|
894
|
+
|
895
|
+
// Vars
|
896
|
+
var that = this
|
897
|
+
, $oldItemWrapper = that.$wrap.find('>.backstretch-item').addClass('deleteable')
|
898
|
+
, oldVideoWrapper = that.videoWrapper
|
899
|
+
, evtOptions = {relatedTarget: that.$container[0]};
|
900
|
+
|
901
|
+
// Trigger the "before" event
|
902
|
+
that.$container.trigger($.Event('backstretch.before', evtOptions), [that, newIndex]);
|
903
|
+
|
904
|
+
// Set the new frame index
|
905
|
+
this.index = newIndex;
|
906
|
+
var selectedImage = that.images[newIndex];
|
907
|
+
|
908
|
+
// Pause the slideshow
|
909
|
+
clearTimeout(that._cycleTimeout);
|
910
|
+
|
911
|
+
// New image
|
912
|
+
|
913
|
+
delete that.videoWrapper; // Current item may not be a video
|
914
|
+
|
915
|
+
var isVideo = isVideoSource(selectedImage);
|
916
|
+
if (isVideo) {
|
917
|
+
that.videoWrapper = new VideoWrapper(selectedImage);
|
918
|
+
that.$item = that.videoWrapper.$video.css('pointer-events', 'none');
|
919
|
+
}
|
920
|
+
else {
|
921
|
+
that.$item = $('<img />');
|
922
|
+
}
|
923
|
+
|
924
|
+
that.$itemWrapper = $('<div class="backstretch-item">')
|
925
|
+
.append(that.$item);
|
926
|
+
|
927
|
+
if (this.options.bypassCss) {
|
928
|
+
that.$itemWrapper.css({
|
929
|
+
'display': 'none'
|
930
|
+
});
|
931
|
+
}
|
932
|
+
else {
|
933
|
+
that.$itemWrapper.css(styles.itemWrapper);
|
934
|
+
that.$item.css(styles.item);
|
935
|
+
}
|
936
|
+
|
937
|
+
that.$item.bind(isVideo ? 'canplay' : 'load', function (e) {
|
938
|
+
var $this = $(this)
|
939
|
+
, $wrapper = $this.parent()
|
940
|
+
, options = $wrapper.data('options');
|
941
|
+
|
942
|
+
if (overrideOptions) {
|
943
|
+
options = $.extend({}, options, overrideOptions);
|
944
|
+
}
|
945
|
+
|
946
|
+
var imgWidth = this.naturalWidth || this.videoWidth || this.width
|
947
|
+
, imgHeight = this.naturalHeight || this.videoHeight || this.height;
|
948
|
+
|
949
|
+
// Save the natural dimensions
|
950
|
+
$wrapper
|
951
|
+
.data('width', imgWidth)
|
952
|
+
.data('height', imgHeight);
|
953
|
+
|
954
|
+
var getOption = function (opt) {
|
955
|
+
return options[opt] !== undefined ?
|
956
|
+
options[opt] :
|
957
|
+
that.options[opt];
|
958
|
+
};
|
959
|
+
|
960
|
+
var transition = getOption('transition');
|
961
|
+
var transitionEasing = getOption('transitionEasing');
|
962
|
+
var transitionDuration = getOption('transitionDuration');
|
963
|
+
|
964
|
+
// Show the image, then delete the old one
|
965
|
+
var bringInNextImage = function () {
|
966
|
+
|
967
|
+
if (oldVideoWrapper) {
|
968
|
+
oldVideoWrapper.stop();
|
969
|
+
oldVideoWrapper.destroy();
|
970
|
+
}
|
971
|
+
|
972
|
+
$oldItemWrapper.remove();
|
973
|
+
|
974
|
+
// Resume the slideshow
|
975
|
+
if (!that.paused && that.images.length > 1) {
|
976
|
+
that.cycle();
|
977
|
+
}
|
978
|
+
|
979
|
+
// Now we can clear the background on the element, to spare memory
|
980
|
+
if (!that.options.bypassCss && !that.isBody) {
|
981
|
+
that.$container.css('background-image', 'none');
|
982
|
+
}
|
983
|
+
|
984
|
+
// Trigger the "after" and "show" events
|
985
|
+
// "show" is being deprecated
|
986
|
+
$(['after', 'show']).each(function () {
|
987
|
+
that.$container.trigger($.Event('backstretch.' + this, evtOptions), [that, newIndex]);
|
988
|
+
});
|
989
|
+
|
990
|
+
if (isVideo) {
|
991
|
+
that.videoWrapper.play();
|
992
|
+
}
|
993
|
+
};
|
994
|
+
|
995
|
+
if ((that.firstShow && !that.options.animateFirst) || !transitionDuration || !transition) {
|
996
|
+
// Avoid transition on first show or if there's no transitionDuration value
|
997
|
+
$wrapper.show();
|
998
|
+
bringInNextImage();
|
999
|
+
}
|
1000
|
+
else {
|
1001
|
+
|
1002
|
+
performTransition({
|
1003
|
+
'new': $wrapper,
|
1004
|
+
old: $oldItemWrapper,
|
1005
|
+
transition: transition,
|
1006
|
+
duration: transitionDuration,
|
1007
|
+
easing: transitionEasing,
|
1008
|
+
complete: bringInNextImage
|
1009
|
+
});
|
1010
|
+
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
that.firstShow = false;
|
1014
|
+
|
1015
|
+
// Resize
|
1016
|
+
that.resize();
|
1017
|
+
});
|
1018
|
+
|
1019
|
+
that.$itemWrapper.appendTo(that.$wrap);
|
1020
|
+
|
1021
|
+
that.$item.attr('alt', selectedImage.alt || '');
|
1022
|
+
that.$itemWrapper.data('options', selectedImage);
|
1023
|
+
|
1024
|
+
if (!isVideo) {
|
1025
|
+
that.$item.attr('src', selectedImage.url);
|
1026
|
+
}
|
1027
|
+
|
1028
|
+
that._currentImage = selectedImage;
|
1029
|
+
|
1030
|
+
return that;
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
, current: function () {
|
1034
|
+
return this.index;
|
1035
|
+
}
|
1036
|
+
|
1037
|
+
, next: function () {
|
1038
|
+
var args = Array.prototype.slice.call(arguments, 0);
|
1039
|
+
args.unshift(this.index < this.images.length - 1 ? this.index + 1 : 0);
|
1040
|
+
return this.show.apply(this, args);
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
, prev: function () {
|
1044
|
+
var args = Array.prototype.slice.call(arguments, 0);
|
1045
|
+
args.unshift(this.index === 0 ? this.images.length - 1 : this.index - 1);
|
1046
|
+
return this.show.apply(this, args);
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
, pause: function () {
|
1050
|
+
// Pause the slideshow
|
1051
|
+
this.paused = true;
|
1052
|
+
|
1053
|
+
if (this.videoWrapper) {
|
1054
|
+
this.videoWrapper.pause();
|
1055
|
+
}
|
1056
|
+
|
1057
|
+
return this;
|
1058
|
+
}
|
1059
|
+
|
1060
|
+
, resume: function () {
|
1061
|
+
// Resume the slideshow
|
1062
|
+
this.paused = false;
|
1063
|
+
|
1064
|
+
if (this.videoWrapper) {
|
1065
|
+
this.videoWrapper.play();
|
1066
|
+
}
|
1067
|
+
|
1068
|
+
this.cycle();
|
1069
|
+
return this;
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
, cycle: function () {
|
1073
|
+
// Start/resume the slideshow
|
1074
|
+
if (this.images.length > 1) {
|
1075
|
+
// Clear the timeout, just in case
|
1076
|
+
clearTimeout(this._cycleTimeout);
|
1077
|
+
|
1078
|
+
var duration = (this._currentImage && this._currentImage.duration) || this.options.duration;
|
1079
|
+
var isVideo = isVideoSource(this._currentImage);
|
1080
|
+
|
1081
|
+
var callNext = function () {
|
1082
|
+
this.$item.off('.cycle');
|
1083
|
+
|
1084
|
+
// Check for paused slideshow
|
1085
|
+
if (!this.paused) {
|
1086
|
+
this.next();
|
1087
|
+
}
|
1088
|
+
};
|
1089
|
+
|
1090
|
+
// Special video handling
|
1091
|
+
if (isVideo) {
|
1092
|
+
|
1093
|
+
// Leave video at last frame
|
1094
|
+
if (!this._currentImage.loop) {
|
1095
|
+
var lastFrameTimeout = 0;
|
1096
|
+
|
1097
|
+
this.$item
|
1098
|
+
.on('playing.cycle', function () {
|
1099
|
+
var player = $(this).data('player');
|
1100
|
+
|
1101
|
+
clearTimeout(lastFrameTimeout);
|
1102
|
+
lastFrameTimeout = setTimeout(function () {
|
1103
|
+
player.pause();
|
1104
|
+
player.$video.trigger('ended');
|
1105
|
+
}, (player.getDuration() - player.getCurrentTime()) * 1000);
|
1106
|
+
})
|
1107
|
+
.on('ended.cycle', function () {
|
1108
|
+
clearTimeout(lastFrameTimeout);
|
1109
|
+
});
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
// On error go to next
|
1113
|
+
this.$item.on('error.cycle initerror.cycle', $.proxy(callNext, this));
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
if (isVideo && !this._currentImage.duration) {
|
1117
|
+
// It's a video - playing until end
|
1118
|
+
this.$item.on('ended.cycle', $.proxy(callNext, this));
|
1119
|
+
|
1120
|
+
}
|
1121
|
+
else {
|
1122
|
+
// Cycling according to specified duration
|
1123
|
+
this._cycleTimeout = setTimeout($.proxy(callNext, this), duration);
|
1124
|
+
}
|
1125
|
+
|
1126
|
+
}
|
1127
|
+
return this;
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
, destroy: function (preserveBackground) {
|
1131
|
+
// Stop the resize events
|
1132
|
+
$(window).off('resize.backstretch orientationchange.backstretch');
|
1133
|
+
|
1134
|
+
// Stop any videos
|
1135
|
+
if (this.videoWrapper) {
|
1136
|
+
this.videoWrapper.destroy();
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
// Clear the timeout
|
1140
|
+
clearTimeout(this._cycleTimeout);
|
1141
|
+
|
1142
|
+
// Remove Backstretch
|
1143
|
+
if (!preserveBackground) {
|
1144
|
+
this.$wrap.remove();
|
1145
|
+
}
|
1146
|
+
this.$container.removeData('backstretch');
|
1147
|
+
}
|
1148
|
+
};
|
1149
|
+
|
1150
|
+
/**
|
1151
|
+
* Video Abstraction Layer
|
1152
|
+
*
|
1153
|
+
* Static methods:
|
1154
|
+
* > VideoWrapper.loadYoutubeAPI() -> Call in order to load the Youtube API.
|
1155
|
+
* An 'youtube_api_load' event will be triggered on $(window) when the API is loaded.
|
1156
|
+
*
|
1157
|
+
* Generic:
|
1158
|
+
* > player.type -> type of the video
|
1159
|
+
* > player.video / player.$video -> contains the element holding the video
|
1160
|
+
* > player.play() -> plays the video
|
1161
|
+
* > player.pause() -> pauses the video
|
1162
|
+
* > player.setCurrentTime(position) -> seeks to a position by seconds
|
1163
|
+
*
|
1164
|
+
* Youtube:
|
1165
|
+
* > player.ytId will contain the youtube ID if the source is a youtube url
|
1166
|
+
* > player.ytReady is a flag telling whether the youtube source is ready for playback
|
1167
|
+
* */
|
1168
|
+
|
1169
|
+
var VideoWrapper = function () { this.init.apply(this, arguments); };
|
1170
|
+
|
1171
|
+
/**
|
1172
|
+
* @param {Object} options
|
1173
|
+
* @param {String|Array<String>|Array<{{src: String, type: String?}}>} options.url
|
1174
|
+
* @param {Boolean} options.loop=false
|
1175
|
+
* @param {Boolean?} options.mute=true
|
1176
|
+
* @param {String?} options.poster
|
1177
|
+
* loop, mute, poster
|
1178
|
+
*/
|
1179
|
+
VideoWrapper.prototype.init = function (options) {
|
1180
|
+
|
1181
|
+
var that = this;
|
1182
|
+
|
1183
|
+
var $video;
|
1184
|
+
|
1185
|
+
var setVideoElement = function () {
|
1186
|
+
that.$video = $video;
|
1187
|
+
that.video = $video[0];
|
1188
|
+
};
|
1189
|
+
|
1190
|
+
// Determine video type
|
1191
|
+
|
1192
|
+
var videoType = 'video';
|
1193
|
+
|
1194
|
+
if (!(options.url instanceof Array) &&
|
1195
|
+
YOUTUBE_REGEXP.test(options.url)) {
|
1196
|
+
videoType = 'youtube';
|
1197
|
+
}
|
1198
|
+
|
1199
|
+
that.type = videoType;
|
1200
|
+
|
1201
|
+
if (videoType === 'youtube') {
|
1202
|
+
|
1203
|
+
// Try to load the API in the meantime
|
1204
|
+
VideoWrapper.loadYoutubeAPI();
|
1205
|
+
|
1206
|
+
that.ytId = options.url.match(YOUTUBE_REGEXP)[2];
|
1207
|
+
var src = 'https://www.youtube.com/embed/' + that.ytId +
|
1208
|
+
'?rel=0&autoplay=0&showinfo=0&controls=0&modestbranding=1' +
|
1209
|
+
'&cc_load_policy=0&disablekb=1&iv_load_policy=3&loop=0' +
|
1210
|
+
'&enablejsapi=1&origin=' + encodeURIComponent(window.location.origin);
|
1211
|
+
|
1212
|
+
that.__ytStartMuted = !!options.mute || options.mute === undefined;
|
1213
|
+
|
1214
|
+
$video = $('<iframe />')
|
1215
|
+
.attr({'src_to_load': src})
|
1216
|
+
.css({'border': 0, 'margin': 0, 'padding': 0})
|
1217
|
+
.data('player', that);
|
1218
|
+
|
1219
|
+
if (options.loop) {
|
1220
|
+
$video.on('ended.loop', function () {
|
1221
|
+
if (!that.__manuallyStopped) {
|
1222
|
+
that.play();
|
1223
|
+
}
|
1224
|
+
});
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
that.ytReady = false;
|
1228
|
+
|
1229
|
+
setVideoElement();
|
1230
|
+
|
1231
|
+
if (window['YT']) {
|
1232
|
+
that._initYoutube();
|
1233
|
+
$video.trigger('initsuccess');
|
1234
|
+
}
|
1235
|
+
else {
|
1236
|
+
$(window).one('youtube_api_load', function () {
|
1237
|
+
that._initYoutube();
|
1238
|
+
$video.trigger('initsuccess');
|
1239
|
+
});
|
1240
|
+
}
|
1241
|
+
|
1242
|
+
}
|
1243
|
+
else {
|
1244
|
+
// Traditional <video> tag with multiple sources
|
1245
|
+
|
1246
|
+
$video = $('<video>')
|
1247
|
+
.prop('autoplay', false)
|
1248
|
+
.prop('controls', false)
|
1249
|
+
.prop('loop', !!options.loop)
|
1250
|
+
.prop('muted', !!options.mute || options.mute === undefined)
|
1251
|
+
|
1252
|
+
// Let the first frames be available before playback, as we do transitions
|
1253
|
+
.prop('preload', 'auto')
|
1254
|
+
.prop('poster', options.poster || '');
|
1255
|
+
|
1256
|
+
var sources = (options.url instanceof Array) ? options.url : [options.url];
|
1257
|
+
|
1258
|
+
for (var i = 0; i < sources.length; i++) {
|
1259
|
+
var sourceItem = sources[i];
|
1260
|
+
if (typeof (sourceItem) === 'string') {
|
1261
|
+
sourceItem = {src: sourceItem};
|
1262
|
+
}
|
1263
|
+
$('<source>')
|
1264
|
+
.attr('src', sourceItem.src)
|
1265
|
+
// Make sure to not specify type if unknown -
|
1266
|
+
// so the browser will try to autodetect.
|
1267
|
+
.attr('type', sourceItem.type || null)
|
1268
|
+
.appendTo($video);
|
1269
|
+
}
|
1270
|
+
|
1271
|
+
if (!$video[0].canPlayType || !sources.length) {
|
1272
|
+
$video.trigger('initerror');
|
1273
|
+
}
|
1274
|
+
else {
|
1275
|
+
$video.trigger('initsuccess');
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
setVideoElement();
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
};
|
1282
|
+
|
1283
|
+
VideoWrapper.prototype._initYoutube = function () {
|
1284
|
+
var that = this;
|
1285
|
+
|
1286
|
+
var YT = window['YT'];
|
1287
|
+
|
1288
|
+
that.$video
|
1289
|
+
.attr('src', that.$video.attr('src_to_load'))
|
1290
|
+
.removeAttr('src_to_load');
|
1291
|
+
|
1292
|
+
// It won't init if it's not in the DOM, so we emulate that
|
1293
|
+
var hasParent = !!that.$video[0].parentNode;
|
1294
|
+
if (!hasParent) {
|
1295
|
+
var $tmpParent = $('<div>').css('display', 'none !important').appendTo(document.body);
|
1296
|
+
that.$video.appendTo($tmpParent);
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
var player = new YT.Player(that.video, {
|
1300
|
+
events: {
|
1301
|
+
'onReady': function () {
|
1302
|
+
|
1303
|
+
if (that.__ytStartMuted) {
|
1304
|
+
player.mute();
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
if (!hasParent) {
|
1308
|
+
// Restore parent to old state - without interrupting any changes
|
1309
|
+
if (that.$video[0].parentNode === $tmpParent[0]) {
|
1310
|
+
that.$video.detach();
|
1311
|
+
}
|
1312
|
+
$tmpParent.remove();
|
1313
|
+
}
|
1314
|
+
|
1315
|
+
that.ytReady = true;
|
1316
|
+
that._updateYoutubeSize();
|
1317
|
+
that.$video.trigger('canplay');
|
1318
|
+
},
|
1319
|
+
'onStateChange': function (event) {
|
1320
|
+
switch (event.data) {
|
1321
|
+
case YT.PlayerState.PLAYING:
|
1322
|
+
that.$video.trigger('playing');
|
1323
|
+
break;
|
1324
|
+
case YT.PlayerState.ENDED:
|
1325
|
+
that.$video.trigger('ended');
|
1326
|
+
break;
|
1327
|
+
case YT.PlayerState.PAUSED:
|
1328
|
+
that.$video.trigger('pause');
|
1329
|
+
break;
|
1330
|
+
case YT.PlayerState.BUFFERING:
|
1331
|
+
that.$video.trigger('waiting');
|
1332
|
+
break;
|
1333
|
+
case YT.PlayerState.CUED:
|
1334
|
+
that.$video.trigger('canplay');
|
1335
|
+
break;
|
1336
|
+
}
|
1337
|
+
},
|
1338
|
+
'onPlaybackQualityChange': function () {
|
1339
|
+
that._updateYoutubeSize();
|
1340
|
+
that.$video.trigger('resize');
|
1341
|
+
},
|
1342
|
+
'onError': function (err) {
|
1343
|
+
that.hasError = true;
|
1344
|
+
that.$video.trigger({'type': 'error', 'error': err});
|
1345
|
+
}
|
1346
|
+
}
|
1347
|
+
});
|
1348
|
+
|
1349
|
+
that.ytPlayer = player;
|
1350
|
+
|
1351
|
+
return that;
|
1352
|
+
};
|
1353
|
+
|
1354
|
+
VideoWrapper.prototype._updateYoutubeSize = function () {
|
1355
|
+
var that = this;
|
1356
|
+
|
1357
|
+
switch (that.ytPlayer.getPlaybackQuality() || 'medium') {
|
1358
|
+
case 'small':
|
1359
|
+
that.video.videoWidth = 426;
|
1360
|
+
that.video.videoHeight = 240;
|
1361
|
+
break;
|
1362
|
+
case 'medium':
|
1363
|
+
that.video.videoWidth = 640;
|
1364
|
+
that.video.videoHeight = 360;
|
1365
|
+
break;
|
1366
|
+
default:
|
1367
|
+
case 'large':
|
1368
|
+
that.video.videoWidth = 854;
|
1369
|
+
that.video.videoHeight = 480;
|
1370
|
+
break;
|
1371
|
+
case 'hd720':
|
1372
|
+
that.video.videoWidth = 1280;
|
1373
|
+
that.video.videoHeight = 720;
|
1374
|
+
break;
|
1375
|
+
case 'hd1080':
|
1376
|
+
that.video.videoWidth = 1920;
|
1377
|
+
that.video.videoHeight = 1080;
|
1378
|
+
break;
|
1379
|
+
case 'highres':
|
1380
|
+
that.video.videoWidth = 2560;
|
1381
|
+
that.video.videoHeight = 1440;
|
1382
|
+
break;
|
1383
|
+
}
|
1384
|
+
|
1385
|
+
return that;
|
1386
|
+
};
|
1387
|
+
|
1388
|
+
VideoWrapper.prototype.play = function () {
|
1389
|
+
var that = this;
|
1390
|
+
|
1391
|
+
that.__manuallyStopped = false;
|
1392
|
+
|
1393
|
+
if (that.type === 'youtube') {
|
1394
|
+
if (that.ytReady) {
|
1395
|
+
that.$video.trigger('play');
|
1396
|
+
that.ytPlayer.playVideo();
|
1397
|
+
}
|
1398
|
+
}
|
1399
|
+
else {
|
1400
|
+
that.video.play();
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
return that;
|
1404
|
+
};
|
1405
|
+
|
1406
|
+
VideoWrapper.prototype.pause = function () {
|
1407
|
+
var that = this;
|
1408
|
+
|
1409
|
+
that.__manuallyStopped = false;
|
1410
|
+
|
1411
|
+
if (that.type === 'youtube') {
|
1412
|
+
if (that.ytReady) {
|
1413
|
+
that.ytPlayer.pauseVideo();
|
1414
|
+
}
|
1415
|
+
}
|
1416
|
+
else {
|
1417
|
+
that.video.pause();
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
return that;
|
1421
|
+
};
|
1422
|
+
|
1423
|
+
VideoWrapper.prototype.stop = function () {
|
1424
|
+
var that = this;
|
1425
|
+
|
1426
|
+
that.__manuallyStopped = true;
|
1427
|
+
|
1428
|
+
if (that.type === 'youtube') {
|
1429
|
+
if (that.ytReady) {
|
1430
|
+
that.ytPlayer.pauseVideo();
|
1431
|
+
that.ytPlayer.seekTo(0);
|
1432
|
+
}
|
1433
|
+
}
|
1434
|
+
else {
|
1435
|
+
that.video.pause();
|
1436
|
+
that.video.currentTime = 0;
|
1437
|
+
}
|
1438
|
+
|
1439
|
+
return that;
|
1440
|
+
};
|
1441
|
+
|
1442
|
+
VideoWrapper.prototype.destroy = function () {
|
1443
|
+
var that = this;
|
1444
|
+
|
1445
|
+
if (that.ytPlayer) {
|
1446
|
+
that.ytPlayer.destroy();
|
1447
|
+
}
|
1448
|
+
|
1449
|
+
that.$video.remove();
|
1450
|
+
|
1451
|
+
return that;
|
1452
|
+
};
|
1453
|
+
|
1454
|
+
VideoWrapper.prototype.getCurrentTime = function (seconds) {
|
1455
|
+
var that = this;
|
1456
|
+
|
1457
|
+
if (that.type === 'youtube') {
|
1458
|
+
if (that.ytReady) {
|
1459
|
+
return that.ytPlayer.getCurrentTime();
|
1460
|
+
}
|
1461
|
+
}
|
1462
|
+
else {
|
1463
|
+
return that.video.currentTime;
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
return 0;
|
1467
|
+
};
|
1468
|
+
|
1469
|
+
VideoWrapper.prototype.setCurrentTime = function (seconds) {
|
1470
|
+
var that = this;
|
1471
|
+
|
1472
|
+
if (that.type === 'youtube') {
|
1473
|
+
if (that.ytReady) {
|
1474
|
+
that.ytPlayer.seekTo(seconds, true);
|
1475
|
+
}
|
1476
|
+
}
|
1477
|
+
else {
|
1478
|
+
that.video.currentTime = seconds;
|
1479
|
+
}
|
1480
|
+
|
1481
|
+
return that;
|
1482
|
+
};
|
1483
|
+
|
1484
|
+
VideoWrapper.prototype.getDuration = function () {
|
1485
|
+
var that = this;
|
1486
|
+
|
1487
|
+
if (that.type === 'youtube') {
|
1488
|
+
if (that.ytReady) {
|
1489
|
+
return that.ytPlayer.getDuration();
|
1490
|
+
}
|
1491
|
+
}
|
1492
|
+
else {
|
1493
|
+
return that.video.duration;
|
1494
|
+
}
|
1495
|
+
|
1496
|
+
return 0;
|
1497
|
+
};
|
1498
|
+
|
1499
|
+
/**
|
1500
|
+
* This will load the youtube API (if not loaded yet)
|
1501
|
+
* Use $(window).one('youtube_api_load', ...) to listen for API loaded event
|
1502
|
+
*/
|
1503
|
+
VideoWrapper.loadYoutubeAPI = function () {
|
1504
|
+
if (window['YT']) {
|
1505
|
+
return;
|
1506
|
+
}
|
1507
|
+
if (!$('script[src*=www\\.youtube\\.com\\/iframe_api]').length) {
|
1508
|
+
$('<script type="text/javascript" src="https://www.youtube.com/iframe_api">').appendTo('body');
|
1509
|
+
}
|
1510
|
+
var ytAPILoadInt = setInterval(function () {
|
1511
|
+
if (window['YT'] && window['YT'].loaded) {
|
1512
|
+
$(window).trigger('youtube_api_load');
|
1513
|
+
clearTimeout(ytAPILoadInt);
|
1514
|
+
}
|
1515
|
+
}, 50);
|
1516
|
+
};
|
1517
|
+
|
1518
|
+
var getDeviceOrientation = function () {
|
1519
|
+
|
1520
|
+
if ('matchMedia' in window) {
|
1521
|
+
if (window.matchMedia("(orientation: portrait)").matches) {
|
1522
|
+
return 'portrait';
|
1523
|
+
}
|
1524
|
+
else if (window.matchMedia("(orientation: landscape)").matches) {
|
1525
|
+
return 'landscape';
|
1526
|
+
}
|
1527
|
+
}
|
1528
|
+
|
1529
|
+
if (screen.height > screen.width) {
|
1530
|
+
return 'portrait';
|
1531
|
+
}
|
1532
|
+
|
1533
|
+
// Even square devices have orientation,
|
1534
|
+
// but a desktop browser may be too old for `matchMedia`.
|
1535
|
+
// Defaulting to `landscape` for the VERY rare case of a square desktop screen is good enough.
|
1536
|
+
return 'landscape';
|
1537
|
+
};
|
1538
|
+
|
1539
|
+
var getWindowOrientation = function () {
|
1540
|
+
if (window.innerHeight > window.innerWidth) {
|
1541
|
+
return 'portrait';
|
1542
|
+
}
|
1543
|
+
if (window.innerWidth > window.innerHeight) {
|
1544
|
+
return 'landscape';
|
1545
|
+
}
|
1546
|
+
|
1547
|
+
return 'square';
|
1548
|
+
};
|
1549
|
+
|
1550
|
+
/* SUPPORTS FIXED POSITION?
|
1551
|
+
*
|
1552
|
+
* Based on code from jQuery Mobile 1.1.0
|
1553
|
+
* http://jquerymobile.com/
|
1554
|
+
*
|
1555
|
+
* In a nutshell, we need to figure out if fixed positioning is supported.
|
1556
|
+
* Unfortunately, this is very difficult to do on iOS, and usually involves
|
1557
|
+
* injecting content, scrolling the page, etc.. It's ugly.
|
1558
|
+
* jQuery Mobile uses this workaround. It's not ideal, but works.
|
1559
|
+
*
|
1560
|
+
* Modified to detect IE6
|
1561
|
+
* ========================= */
|
1562
|
+
|
1563
|
+
var supportsFixedPosition = (function () {
|
1564
|
+
var ua = navigator.userAgent
|
1565
|
+
, platform = navigator.platform
|
1566
|
+
// Rendering engine is Webkit, and capture major version
|
1567
|
+
, wkmatch = ua.match(/AppleWebKit\/([0-9]+)/)
|
1568
|
+
, wkversion = !!wkmatch && wkmatch[1]
|
1569
|
+
, ffmatch = ua.match(/Fennec\/([0-9]+)/)
|
1570
|
+
, ffversion = !!ffmatch && ffmatch[1]
|
1571
|
+
, operammobilematch = ua.match(/Opera Mobi\/([0-9]+)/)
|
1572
|
+
, omversion = !!operammobilematch && operammobilematch[1]
|
1573
|
+
, iematch = ua.match(/MSIE ([0-9]+)/)
|
1574
|
+
, ieversion = !!iematch && iematch[1];
|
1575
|
+
|
1576
|
+
return !(
|
1577
|
+
// iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
|
1578
|
+
((platform.indexOf("iPhone") > -1 || platform.indexOf("iPad") > -1 || platform.indexOf(
|
1579
|
+
"iPod") > -1) && wkversion && wkversion < 534) ||
|
1580
|
+
|
1581
|
+
// Opera Mini
|
1582
|
+
(window.operamini && ({}).toString.call(window.operamini) === "[object OperaMini]") ||
|
1583
|
+
(operammobilematch && omversion < 7458) ||
|
1584
|
+
|
1585
|
+
//Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
|
1586
|
+
(ua.indexOf("Android") > -1 && wkversion && wkversion < 533) ||
|
1587
|
+
|
1588
|
+
// Firefox Mobile before 6.0 -
|
1589
|
+
(ffversion && ffversion < 6) ||
|
1590
|
+
|
1591
|
+
// WebOS less than 3
|
1592
|
+
("palmGetResource" in window && wkversion && wkversion < 534) ||
|
1593
|
+
|
1594
|
+
// MeeGo
|
1595
|
+
(ua.indexOf("MeeGo") > -1 && ua.indexOf("NokiaBrowser/8.5.0") > -1) ||
|
1596
|
+
|
1597
|
+
// IE6
|
1598
|
+
(ieversion && ieversion <= 6)
|
1599
|
+
);
|
1600
|
+
}());
|
1601
|
+
|
1602
|
+
}(jQuery, window));
|