phcthemes_admin_panel_pack 4.0.7 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (313) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -20
  3. data/README.md +2 -0
  4. data/Rakefile +8 -8
  5. data/app/assets/config/phcthemes_admin_panel_pack_manifest.js +9 -9
  6. data/app/assets/javascripts/common/backstretch/jquery.backstretch.js +1602 -1602
  7. data/app/assets/javascripts/common/bootstrap/bootstrap.bundle.js +7023 -7023
  8. data/app/assets/javascripts/common/bootstrap/bootstrap.three.js +2377 -2377
  9. data/app/assets/javascripts/common/bootstrap-datepicker/bootstrap-datepicker.js +2039 -2039
  10. data/app/assets/javascripts/common/bootstrap-markdown/bootstrap-markdown.js +1390 -1390
  11. data/app/assets/javascripts/common/bootstrap-select/bootstrap-select.js +0 -0
  12. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-am_ET.js +0 -0
  13. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-am_ET.js.map +0 -0
  14. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-am_ET.min.js +7 -7
  15. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ar_AR.js +0 -0
  16. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ar_AR.js.map +0 -0
  17. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ar_AR.min.js +7 -7
  18. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-bg_BG.js +0 -0
  19. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-bg_BG.js.map +0 -0
  20. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-bg_BG.min.js +7 -7
  21. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-cs_CZ.js +0 -0
  22. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-cs_CZ.js.map +0 -0
  23. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-cs_CZ.min.js +7 -7
  24. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-da_DK.js +0 -0
  25. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-da_DK.js.map +0 -0
  26. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-da_DK.min.js +7 -7
  27. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-de_DE.js +0 -0
  28. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-de_DE.js.map +0 -0
  29. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-de_DE.min.js +7 -7
  30. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-en_US.js +0 -0
  31. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-en_US.js.map +0 -0
  32. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-en_US.min.js +7 -7
  33. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_CL.js +0 -0
  34. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_CL.js.map +0 -0
  35. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_CL.min.js +7 -7
  36. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_ES.js +0 -0
  37. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_ES.js.map +0 -0
  38. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-es_ES.min.js +7 -7
  39. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-et_EE.js +0 -0
  40. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-et_EE.js.map +0 -0
  41. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-et_EE.min.js +7 -7
  42. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-eu.js +0 -0
  43. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-eu.js.map +0 -0
  44. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-eu.min.js +7 -7
  45. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fa_IR.js +0 -0
  46. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fa_IR.js.map +0 -0
  47. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fa_IR.min.js +7 -7
  48. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fi_FI.js +0 -0
  49. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fi_FI.js.map +0 -0
  50. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fi_FI.min.js +7 -7
  51. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fr_FR.js +0 -0
  52. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fr_FR.js.map +0 -0
  53. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-fr_FR.min.js +7 -7
  54. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hr_HR.js +0 -0
  55. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hr_HR.js.map +0 -0
  56. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hr_HR.min.js +7 -7
  57. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hu_HU.js +0 -0
  58. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hu_HU.js.map +0 -0
  59. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-hu_HU.min.js +7 -7
  60. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-id_ID.js +0 -0
  61. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-id_ID.js.map +0 -0
  62. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-id_ID.min.js +7 -7
  63. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-it_IT.js +0 -0
  64. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-it_IT.js.map +0 -0
  65. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-it_IT.min.js +7 -7
  66. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ja_JP.js +0 -0
  67. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ja_JP.js.map +0 -0
  68. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ja_JP.min.js +7 -7
  69. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-kh_KM.js +0 -0
  70. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-kh_KM.js.map +0 -0
  71. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-kh_KM.min.js +7 -7
  72. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ko_KR.js +0 -0
  73. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ko_KR.js.map +0 -0
  74. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ko_KR.min.js +7 -7
  75. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lt_LT.js +0 -0
  76. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lt_LT.js.map +0 -0
  77. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lt_LT.min.js +7 -7
  78. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lv_LV.js +0 -0
  79. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lv_LV.js.map +0 -0
  80. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-lv_LV.min.js +7 -7
  81. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nb_NO.js +0 -0
  82. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nb_NO.js.map +0 -0
  83. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nb_NO.min.js +7 -7
  84. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nl_NL.js +0 -0
  85. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nl_NL.js.map +0 -0
  86. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-nl_NL.min.js +7 -7
  87. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pl_PL.js +0 -0
  88. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pl_PL.js.map +0 -0
  89. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pl_PL.min.js +7 -7
  90. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_BR.js +0 -0
  91. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_BR.js.map +0 -0
  92. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_BR.min.js +7 -7
  93. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_PT.js +0 -0
  94. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_PT.js.map +0 -0
  95. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-pt_PT.min.js +7 -7
  96. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ro_RO.js +0 -0
  97. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ro_RO.js.map +0 -0
  98. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ro_RO.min.js +7 -7
  99. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ru_RU.js +0 -0
  100. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ru_RU.js.map +0 -0
  101. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ru_RU.min.js +7 -7
  102. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sk_SK.js +0 -0
  103. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sk_SK.js.map +0 -0
  104. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sk_SK.min.js +7 -7
  105. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sl_SI.js +0 -0
  106. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sl_SI.js.map +0 -0
  107. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sl_SI.min.js +7 -7
  108. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sv_SE.js +0 -0
  109. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sv_SE.js.map +0 -0
  110. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-sv_SE.min.js +7 -7
  111. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-tr_TR.js +0 -0
  112. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-tr_TR.js.map +0 -0
  113. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-tr_TR.min.js +7 -7
  114. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ua_UA.js +0 -0
  115. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ua_UA.js.map +0 -0
  116. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-ua_UA.min.js +7 -7
  117. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-vi_VN.js +0 -0
  118. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-vi_VN.js.map +0 -0
  119. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-vi_VN.min.js +7 -7
  120. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_CN.js +0 -0
  121. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_CN.js.map +0 -0
  122. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_CN.min.js +7 -7
  123. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_TW.js +0 -0
  124. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_TW.js.map +0 -0
  125. data/app/assets/javascripts/common/bootstrap-select/i18n/defaults-zh_TW.min.js +7 -7
  126. data/app/assets/javascripts/common/chartjs/chart.js +0 -0
  127. data/app/assets/javascripts/common/ckeditor/ckeditor.js +6 -6
  128. data/app/assets/javascripts/common/ckeditor/ckeditor.js.map +0 -0
  129. data/app/assets/javascripts/common/ckeditor/translations/af.js +0 -0
  130. data/app/assets/javascripts/common/ckeditor/translations/ar.js +0 -0
  131. data/app/assets/javascripts/common/ckeditor/translations/ast.js +0 -0
  132. data/app/assets/javascripts/common/ckeditor/translations/az.js +0 -0
  133. data/app/assets/javascripts/common/ckeditor/translations/bg.js +0 -0
  134. data/app/assets/javascripts/common/ckeditor/translations/ca.js +0 -0
  135. data/app/assets/javascripts/common/ckeditor/translations/cs.js +0 -0
  136. data/app/assets/javascripts/common/ckeditor/translations/da.js +0 -0
  137. data/app/assets/javascripts/common/ckeditor/translations/de-ch.js +0 -0
  138. data/app/assets/javascripts/common/ckeditor/translations/de.js +0 -0
  139. data/app/assets/javascripts/common/ckeditor/translations/el.js +0 -0
  140. data/app/assets/javascripts/common/ckeditor/translations/en-au.js +0 -0
  141. data/app/assets/javascripts/common/ckeditor/translations/en-gb.js +0 -0
  142. data/app/assets/javascripts/common/ckeditor/translations/eo.js +0 -0
  143. data/app/assets/javascripts/common/ckeditor/translations/es.js +0 -0
  144. data/app/assets/javascripts/common/ckeditor/translations/et.js +0 -0
  145. data/app/assets/javascripts/common/ckeditor/translations/eu.js +0 -0
  146. data/app/assets/javascripts/common/ckeditor/translations/fa.js +0 -0
  147. data/app/assets/javascripts/common/ckeditor/translations/fi.js +0 -0
  148. data/app/assets/javascripts/common/ckeditor/translations/fr.js +0 -0
  149. data/app/assets/javascripts/common/ckeditor/translations/gl.js +0 -0
  150. data/app/assets/javascripts/common/ckeditor/translations/gu.js +0 -0
  151. data/app/assets/javascripts/common/ckeditor/translations/he.js +0 -0
  152. data/app/assets/javascripts/common/ckeditor/translations/hr.js +0 -0
  153. data/app/assets/javascripts/common/ckeditor/translations/hu.js +0 -0
  154. data/app/assets/javascripts/common/ckeditor/translations/id.js +0 -0
  155. data/app/assets/javascripts/common/ckeditor/translations/it.js +0 -0
  156. data/app/assets/javascripts/common/ckeditor/translations/ja.js +0 -0
  157. data/app/assets/javascripts/common/ckeditor/translations/km.js +0 -0
  158. data/app/assets/javascripts/common/ckeditor/translations/kn.js +0 -0
  159. data/app/assets/javascripts/common/ckeditor/translations/ko.js +0 -0
  160. data/app/assets/javascripts/common/ckeditor/translations/ku.js +0 -0
  161. data/app/assets/javascripts/common/ckeditor/translations/lt.js +0 -0
  162. data/app/assets/javascripts/common/ckeditor/translations/lv.js +0 -0
  163. data/app/assets/javascripts/common/ckeditor/translations/nb.js +0 -0
  164. data/app/assets/javascripts/common/ckeditor/translations/ne.js +0 -0
  165. data/app/assets/javascripts/common/ckeditor/translations/nl.js +0 -0
  166. data/app/assets/javascripts/common/ckeditor/translations/no.js +0 -0
  167. data/app/assets/javascripts/common/ckeditor/translations/oc.js +0 -0
  168. data/app/assets/javascripts/common/ckeditor/translations/pl.js +0 -0
  169. data/app/assets/javascripts/common/ckeditor/translations/pt-br.js +0 -0
  170. data/app/assets/javascripts/common/ckeditor/translations/pt.js +0 -0
  171. data/app/assets/javascripts/common/ckeditor/translations/ro.js +0 -0
  172. data/app/assets/javascripts/common/ckeditor/translations/ru.js +0 -0
  173. data/app/assets/javascripts/common/ckeditor/translations/si.js +0 -0
  174. data/app/assets/javascripts/common/ckeditor/translations/sk.js +0 -0
  175. data/app/assets/javascripts/common/ckeditor/translations/sl.js +0 -0
  176. data/app/assets/javascripts/common/ckeditor/translations/sq.js +0 -0
  177. data/app/assets/javascripts/common/ckeditor/translations/sr-latn.js +0 -0
  178. data/app/assets/javascripts/common/ckeditor/translations/sr.js +0 -0
  179. data/app/assets/javascripts/common/ckeditor/translations/sv.js +0 -0
  180. data/app/assets/javascripts/common/ckeditor/translations/th.js +0 -0
  181. data/app/assets/javascripts/common/ckeditor/translations/tr.js +0 -0
  182. data/app/assets/javascripts/common/ckeditor/translations/tt.js +0 -0
  183. data/app/assets/javascripts/common/ckeditor/translations/ug.js +0 -0
  184. data/app/assets/javascripts/common/ckeditor/translations/uk.js +0 -0
  185. data/app/assets/javascripts/common/ckeditor/translations/vi.js +0 -0
  186. data/app/assets/javascripts/common/ckeditor/translations/zh-cn.js +0 -0
  187. data/app/assets/javascripts/common/ckeditor/translations/zh.js +0 -0
  188. data/app/assets/javascripts/common/clipboardjs/clipboard.js +977 -977
  189. data/app/assets/javascripts/common/covervid/covervid.js +94 -94
  190. data/app/assets/javascripts/common/custom/custom.js +0 -0
  191. data/app/assets/javascripts/common/datatables/datatables.js +15310 -15310
  192. data/app/assets/javascripts/common/daterangepicker/daterangepicker.js +1565 -1565
  193. data/app/assets/javascripts/common/fastclick/fastclick.js +841 -841
  194. data/app/assets/javascripts/common/flexslider/jquery.flexslider.js +1252 -1252
  195. data/app/assets/javascripts/common/greenstock/greensock.js +35 -35
  196. data/app/assets/javascripts/common/html5sortable/jquery.sortable.js +98 -98
  197. data/app/assets/javascripts/common/icheck/icheck.js +509 -509
  198. data/app/assets/javascripts/common/imagesloaded/imagesloaded.pkgd.js +497 -497
  199. data/app/assets/javascripts/common/isotope/isotope.pkgd.js +3563 -3563
  200. data/app/assets/javascripts/common/jquery/jquery-3.4.1.js +10598 -10598
  201. data/app/assets/javascripts/common/jquery-countdown/jquery.countdown.js +245 -245
  202. data/app/assets/javascripts/common/jquery-filterizer/jquery.filterizr.min.js +0 -0
  203. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.autogrow.js +37 -37
  204. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.charcounter.js +53 -53
  205. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.checkbox.js +54 -54
  206. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.datepicker.js +59 -59
  207. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.js +823 -823
  208. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.masked.js +46 -46
  209. data/app/assets/javascripts/common/jquery-jeditable/jquery.jeditable.time.js +71 -71
  210. data/app/assets/javascripts/common/jquery-jvectormap/jquery-jvectormap.js +44 -44
  211. data/app/assets/javascripts/common/jquery-placeholder/jquery.placeholder.js +281 -281
  212. data/app/assets/javascripts/common/jquery-slimscroll/jquery.slimscroll.js +474 -474
  213. data/app/assets/javascripts/common/jquery-sparkline/jquery.sparkline.js +3054 -3054
  214. data/app/assets/javascripts/common/jquery-ui/jquery-ui.js +18705 -18705
  215. data/app/assets/javascripts/common/jquery-validation/jquery.validate.js +0 -0
  216. data/app/assets/javascripts/common/jqvmap/jquery.vmap.js +1281 -1281
  217. data/app/assets/javascripts/common/jqvmap/jquery.vmap.min.js +9 -9
  218. data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.africa.js +2 -2
  219. data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.asia.js +2 -2
  220. data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.australia.js +2 -2
  221. data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.europe.js +2 -2
  222. data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.north-america.js +2 -2
  223. data/app/assets/javascripts/common/jqvmap/maps/continents/jquery.vmap.south-america.js +2 -2
  224. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.algeria.js +2 -2
  225. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.argentina.js +1 -1
  226. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.brazil.js +2 -2
  227. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.canada.js +1 -1
  228. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.europe.js +2 -2
  229. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.france.js +1 -1
  230. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.germany.js +2 -2
  231. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.greece.js +1 -1
  232. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.iran.js +6 -6
  233. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.iraq.js +1 -1
  234. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.russia.js +2 -2
  235. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.tunisia.js +2 -2
  236. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.turkey.js +11 -11
  237. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.usa.js +2 -2
  238. data/app/assets/javascripts/common/jqvmap/maps/jquery.vmap.world.js +2 -2
  239. data/app/assets/javascripts/common/js-cookie/js.cookie.js +165 -165
  240. data/app/assets/javascripts/common/layerslider/layerslider.kreaturamedia.jquery.js +12 -12
  241. data/app/assets/javascripts/common/layerslider/layerslider.origami.js +12 -12
  242. data/app/assets/javascripts/common/layerslider/layerslider.timeline.js +12 -12
  243. data/app/assets/javascripts/common/layerslider/layerslider.transitions.js +12 -12
  244. data/app/assets/javascripts/common/lazysizes/lazysizes.js +754 -754
  245. data/app/assets/javascripts/common/leaflet/leaflet.js +4 -4
  246. data/app/assets/javascripts/common/magnific-popup/jquery.magnific-popup.js +1859 -1859
  247. data/app/assets/javascripts/common/mapbox/mapbox.js +51 -51
  248. data/app/assets/javascripts/common/metismenu/metisMenu.js +340 -340
  249. data/app/assets/javascripts/common/moderizer/modernizr.js +11 -11
  250. data/app/assets/javascripts/common/nouislider/nouislider.js +2637 -2637
  251. data/app/assets/javascripts/common/owl-carousel/owl.carousel.js +3448 -3448
  252. data/app/assets/javascripts/common/pace/pace.js +935 -935
  253. data/app/assets/javascripts/common/paroller/jquery.paroller.js +228 -228
  254. data/app/assets/javascripts/common/particlejs/particles.js +1540 -1540
  255. data/app/assets/javascripts/common/perfect-scrollbar/perfect-scrollbar.common.js +1318 -1318
  256. data/app/assets/javascripts/common/perfect-scrollbar/perfect-scrollbar.esm.js +1316 -1316
  257. data/app/assets/javascripts/common/perfect-scrollbar/perfect-scrollbar.js +1324 -1324
  258. data/app/assets/javascripts/common/plyr/plyr.js +9137 -9137
  259. data/app/assets/javascripts/common/rangeslider/rangeslider.js +498 -498
  260. data/app/assets/javascripts/common/retina/retina.js +100 -100
  261. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.actions.js +0 -0
  262. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.carousel.js +0 -0
  263. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.kenburn.js +0 -0
  264. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.layeranimation.js +0 -0
  265. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.migration.js +0 -0
  266. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.navigation.js +0 -0
  267. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.parallax.js +0 -0
  268. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.slideanims.js +0 -0
  269. data/app/assets/javascripts/common/rev-slider/extensions/revolution.extension.video.js +0 -0
  270. data/app/assets/javascripts/common/rev-slider/jquery.themepunch.revolution.js +0 -0
  271. data/app/assets/javascripts/common/rev-slider/jquery.themepunch.tools.min.js +0 -0
  272. data/app/assets/javascripts/common/scrollme/jquery.scrollme.js +455 -455
  273. data/app/assets/javascripts/common/scrollup/jquery.scrollUp.js +168 -168
  274. data/app/assets/javascripts/common/select2/select2.full.js +6597 -6597
  275. data/app/assets/javascripts/common/selectbox/jquery.selectBox.js +1091 -1091
  276. data/app/assets/javascripts/common/slick/slick.js +3004 -3004
  277. data/app/assets/javascripts/common/smooth-scroll/SmoothScroll.js +788 -788
  278. data/app/assets/javascripts/common/spectrum/spectrum.js +2323 -2323
  279. data/app/assets/javascripts/common/stepper/jquery.fs.stepper.js +339 -339
  280. data/app/assets/javascripts/common/swiper/swiper.js +8124 -8124
  281. data/app/assets/javascripts/common/toaster/toastr.js +476 -476
  282. data/app/assets/javascripts/common/typed/typed.js +1044 -1044
  283. data/app/assets/javascripts/common/visable/jquery.visible.js +68 -68
  284. data/app/assets/javascripts/common/waypoints/jquery.waypoints.js +661 -661
  285. data/app/assets/javascripts/common/wow/wow.js +508 -508
  286. data/app/assets/javascripts/phcthemes_admin_panel_pack_adminlte.js +12 -12
  287. data/app/assets/javascripts/phcthemes_admin_panel_pack_boomerang.js +0 -0
  288. data/app/assets/javascripts/phcthemes_admin_panel_pack_coloradmin.js +5 -5
  289. data/app/assets/javascripts/phcthemes_admin_panel_pack_inspinia.js +10 -10
  290. data/app/assets/javascripts/phcthemes_admin_panel_pack_metronic.js +6 -6
  291. data/app/assets/javascripts/phcthemes_admin_panel_pack_quilpro.js +5 -5
  292. data/app/assets/javascripts/phcthemes_admin_panel_pack_starlight.js +5 -5
  293. data/app/assets/javascripts/themes/adminlte/theme/adminlte.js +1141 -1141
  294. data/app/assets/javascripts/themes/coloradmin/theme/color_admin_app.min.js +0 -0
  295. data/app/assets/javascripts/themes/coloradmin/theme/color_admin_default.js +0 -0
  296. data/app/assets/javascripts/themes/inspinia/theme/inspinia.js +279 -279
  297. data/app/assets/javascripts/themes/metronic/theme/plugins.bundle.js +0 -0
  298. data/app/assets/javascripts/themes/metronic/theme/prismjs.bundle.js +1922 -1922
  299. data/app/assets/javascripts/themes/metronic/theme/scripts.bundle.js +0 -0
  300. data/app/assets/javascripts/themes/metronic/theme/widgets.js +0 -0
  301. data/app/assets/stylesheets/common/hanna_hearts/hanna_hearts.scss +0 -0
  302. data/app/assets/stylesheets/phcthemes_admin_panel_pack_adminlte.scss +16 -16
  303. data/app/assets/stylesheets/phcthemes_admin_panel_pack_boomerang.scss +27 -27
  304. data/app/assets/stylesheets/phcthemes_admin_panel_pack_coloradmin.scss +11 -11
  305. data/app/assets/stylesheets/phcthemes_admin_panel_pack_inspinia.scss +18 -18
  306. data/app/assets/stylesheets/phcthemes_admin_panel_pack_metronic.scss +15 -15
  307. data/app/assets/stylesheets/phcthemes_admin_panel_pack_quilpro.scss +19 -19
  308. data/app/assets/stylesheets/phcthemes_admin_panel_pack_starlight.scss +15 -15
  309. data/lib/phcthemes_admin_panel_pack/engine.rb +20 -20
  310. data/lib/phcthemes_admin_panel_pack/version.rb +3 -3
  311. data/lib/phcthemes_admin_panel_pack.rb +6 -6
  312. data/lib/tasks/phcthemes_admin_panel_pack_tasks.rake +4 -4
  313. metadata +3 -3
@@ -1,1602 +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));
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));