From 87bbfc33d37c747a0baafe9dc8e0e6d6905fc303 Mon Sep 17 00:00:00 2001 From: DoarMihai Date: Mon, 10 Feb 2025 01:58:12 +0200 Subject: [PATCH] progress --- .../ItemProcessing/FetchItemDataCommand.php | 47 +- .../Controllers/Auth/RegisterController.php | 1 + app/Http/Controllers/CelebrityController.php | 29 +- .../Controllers/Forum/ThreadsController.php | 12 +- .../Controllers/Forum/TopicsController.php | 6 +- app/Http/Controllers/ShowController.php | 25 + app/Http/Requests/Forum/TopicRequest.php | 28 + app/Livewire/ShowPage/Recommended.php | 24 + app/Livewire/ShowPage/Similar.php | 24 + app/Livewire/ShowPage/Tabs/Cast.php | 36 + app/Livewire/ShowPage/Tabs/Crew.php | 37 + app/Livewire/ShowPage/Tabs/Details.php | 15 + app/Livewire/ShowPage/Tabs/Releases.php | 13 + app/Models/Forum/Topic.php | 11 +- app/Models/Image.php | 3 + app/Models/ItemToFetchJobs.php | 8 - app/Models/Show.php | 60 +- .../MediaProcessing/FactoryService.php | 4 +- .../MovieProcessingService.php | 23 + .../MediaProcessing/ShowProcessingService.php | 195 +- ...153704_create_item_to_fetch_jobs_table.php | 1 - .../2025_01_27_191019_create_topics_table.php | 2 + package-lock.json | 24 +- package.json | 4 +- public/img/imdb.png | Bin 0 -> 10602 bytes public/img/tmdb.webp | Bin 0 -> 2104 bytes public/img/tv_rage.png | Bin 0 -> 11505 bytes public/img/tvdb.png | Bin 0 -> 13876 bytes public/img/wikidata.png | Bin 0 -> 1393 bytes .../js/OwlCarousel2-2.3.4/.gitattributes | 5 + resources/js/OwlCarousel2-2.3.4/.gitignore | 18 + resources/js/OwlCarousel2-2.3.4/.travis.yml | 14 + .../js/OwlCarousel2-2.3.4/CONTRIBUTING.md | 88 + resources/js/OwlCarousel2-2.3.4/Gruntfile.js | 320 + .../js/OwlCarousel2-2.3.4/ISSUE_TEMPLATE.md | 14 + resources/js/OwlCarousel2-2.3.4/LICENSE | 23 + resources/js/OwlCarousel2-2.3.4/README.md | 122 + resources/js/OwlCarousel2-2.3.4/ROADMAP.md | 57 + resources/js/OwlCarousel2-2.3.4/_config.json | 30 + resources/js/OwlCarousel2-2.3.4/bower.json | 13 + resources/js/OwlCarousel2-2.3.4/dist/LICENSE | 23 + .../js/OwlCarousel2-2.3.4/dist/README.md | 122 + .../dist/assets/ajax-loader.gif | Bin 0 -> 3208 bytes .../dist/assets/owl.carousel.css | 186 + .../dist/assets/owl.carousel.min.css | 6 + .../dist/assets/owl.theme.default.css | 50 + .../dist/assets/owl.theme.default.min.css | 6 + .../dist/assets/owl.theme.green.css | 50 + .../dist/assets/owl.theme.green.min.css | 6 + .../dist/assets/owl.video.play.png | Bin 0 -> 4976 bytes .../OwlCarousel2-2.3.4/dist/owl.carousel.js | 3452 +++++++++ .../dist/owl.carousel.min.js | 7 + .../docs/assets/css/animate.css | 3303 +++++++++ .../docs/assets/css/docs.theme.min.css | 1 + .../docs/assets/img/bird_blue_32.png | Bin 0 -> 1348 bytes .../docs/assets/img/download.png | Bin 0 -> 3749 bytes .../docs/assets/img/feature-drag.png | Bin 0 -> 8374 bytes .../docs/assets/img/feature-modern.png | Bin 0 -> 11758 bytes .../docs/assets/img/feature-module.png | Bin 0 -> 13307 bytes .../docs/assets/img/feature-options.png | Bin 0 -> 6695 bytes .../docs/assets/img/feature-responsive.png | Bin 0 -> 7539 bytes .../docs/assets/img/feature-zombie.png | Bin 0 -> 9671 bytes .../docs/assets/img/owl-logo.png | Bin 0 -> 13701 bytes .../docs/assets/img/twitter_25.png | Bin 0 -> 4429 bytes .../OwlCarousel2-2.3.4/docs/assets/js/app.js | 32 + .../docs/assets/js/foundation.min.js | 3 + .../docs/assets/owlcarousel/README.md | 122 + .../assets/owlcarousel/assets/ajax-loader.gif | Bin 0 -> 3208 bytes .../owlcarousel/assets/owl.carousel.css | 186 + .../owlcarousel/assets/owl.carousel.min.css | 6 + .../owlcarousel/assets/owl.theme.default.css | 50 + .../assets/owl.theme.default.min.css | 6 + .../owlcarousel/assets/owl.theme.green.css | 50 + .../assets/owl.theme.green.min.css | 6 + .../owlcarousel/assets/owl.video.play.png | Bin 0 -> 4976 bytes .../docs/assets/owlcarousel/owl.carousel.js | 3448 +++++++++ .../assets/owlcarousel/owl.carousel.min.js | 7 + .../docs/assets/vendors/foundation.min.js | 3 + .../docs/assets/vendors/highlight.js | 1 + .../docs/assets/vendors/jquery.min.js | 2 + .../docs/assets/vendors/jquery.min.map | 1 + .../assets/vendors/jquery.mousewheel.min.js | 8 + .../docs/demos/animate.html | 272 + .../docs/demos/autoheight.html | 165 + .../docs/demos/autoplay.html | 186 + .../docs/demos/autowidth.html | 185 + .../OwlCarousel2-2.3.4/docs/demos/basic.html | 199 + .../OwlCarousel2-2.3.4/docs/demos/center.html | 239 + .../OwlCarousel2-2.3.4/docs/demos/demos.html | 198 + .../OwlCarousel2-2.3.4/docs/demos/events.html | 207 + .../docs/demos/lazyLoad.html | 165 + .../OwlCarousel2-2.3.4/docs/demos/merge.html | 202 + .../docs/demos/mousewheel.html | 209 + .../docs/demos/responsive.html | 297 + .../js/OwlCarousel2-2.3.4/docs/demos/rtl.html | 202 + .../docs/demos/stagepadding.html | 202 + .../OwlCarousel2-2.3.4/docs/demos/test.html | 144 + .../docs/demos/urlhashnav.html | 190 + .../OwlCarousel2-2.3.4/docs/demos/video.html | 189 + .../docs/docs/api-classes.html | 227 + .../docs/docs/api-events.html | 358 + .../docs/docs/api-options.html | 395 ++ .../docs/docs/dev-buildin-plugins.html | 157 + .../docs/docs/dev-external.html | 151 + .../docs/docs/dev-plugin-api.html | 160 + .../docs/docs/dev-styles.html | 171 + .../docs/docs/started-faq.html | 162 + .../docs/docs/started-installation.html | 173 + .../docs/docs/started-welcome.html | 196 + .../docs/docs/support-changelog.html | 169 + .../docs/docs/support-contact.html | 140 + .../docs/docs/support-contributing.html | 162 + .../js/OwlCarousel2-2.3.4/docs/index.html | 239 + .../docs_src/assets/css/animate.css | 3303 +++++++++ .../docs_src/assets/img/bird_blue_32.png | Bin 0 -> 1348 bytes .../docs_src/assets/img/download.png | Bin 0 -> 3749 bytes .../docs_src/assets/img/feature-drag.png | Bin 0 -> 8374 bytes .../docs_src/assets/img/feature-modern.png | Bin 0 -> 11758 bytes .../docs_src/assets/img/feature-module.png | Bin 0 -> 13307 bytes .../docs_src/assets/img/feature-options.png | Bin 0 -> 6695 bytes .../assets/img/feature-responsive.png | Bin 0 -> 7539 bytes .../docs_src/assets/img/feature-zombie.png | Bin 0 -> 9671 bytes .../docs_src/assets/img/owl-logo.png | Bin 0 -> 13701 bytes .../docs_src/assets/img/twitter_25.png | Bin 0 -> 4429 bytes .../docs_src/assets/js/app.js | 32 + .../docs_src/assets/js/foundation.min.js | 3 + .../docs_src/assets/scss/_settings.scss | 1279 ++++ .../docs_src/assets/scss/custom.scss | 364 + .../docs_src/assets/scss/demos.scss | 45 + .../docs_src/assets/scss/docs.scss | 53 + .../docs_src/assets/scss/docs.theme.scss | 7 + .../docs_src/assets/scss/highlight.scss | 134 + .../docs_src/assets/vendors/foundation.min.js | 3 + .../docs_src/assets/vendors/highlight.js | 1 + .../docs_src/assets/vendors/jquery.min.js | 2 + .../docs_src/assets/vendors/jquery.min.map | 1 + .../assets/vendors/jquery.mousewheel.min.js | 8 + .../docs_src/data/classes.json | 86 + .../docs_src/data/events.json | 173 + .../docs_src/data/features.json | 33 + .../docs_src/data/options.json | 308 + .../docs_src/helpers/modulo.js | 0 .../docs_src/helpers/test.js | 13 + .../docs_src/templates/layouts/demos.hbs | 37 + .../docs_src/templates/layouts/docs.hbs | 38 + .../docs_src/templates/layouts/home.hbs | 35 + .../templates/pages/demos/animate.hbs | 165 + .../templates/pages/demos/autoheight.hbs | 63 + .../templates/pages/demos/autoplay.hbs | 85 + .../templates/pages/demos/autowidth.hbs | 75 + .../docs_src/templates/pages/demos/basic.hbs | 95 + .../docs_src/templates/pages/demos/center.hbs | 116 + .../docs_src/templates/pages/demos/demos.hbs | 73 + .../docs_src/templates/pages/demos/events.hbs | 103 + .../templates/pages/demos/lazyLoad.hbs | 93 + .../docs_src/templates/pages/demos/merge.hbs | 92 + .../templates/pages/demos/mousewheel.hbs | 109 + .../templates/pages/demos/responsive.hbs | 214 + .../docs_src/templates/pages/demos/rtl.hbs | 102 + .../templates/pages/demos/stagepadding.hbs | 102 + .../docs_src/templates/pages/demos/test.hbs | 43 + .../templates/pages/demos/urlhashnav.hbs | 73 + .../docs_src/templates/pages/demos/video.hbs | 99 + .../templates/pages/docs/api-classes.hbs | 58 + .../templates/pages/docs/api-events.hbs | 96 + .../templates/pages/docs/api-options.hbs | 34 + .../pages/docs/dev-buildin-plugins.hbs | 123 + .../templates/pages/docs/dev-external.hbs | 33 + .../templates/pages/docs/dev-plugin-api.hbs | 55 + .../templates/pages/docs/dev-styles.hbs | 62 + .../templates/pages/docs/started-faq.hbs | 60 + .../pages/docs/started-installation.hbs | 71 + .../templates/pages/docs/started-welcome.hbs | 90 + .../pages/docs/support-changelog.hbs | 54 + .../templates/pages/docs/support-contact.hbs | 23 + .../pages/docs/support-contributing.hbs | 62 + .../docs_src/templates/pages/index.hbs | 9 + .../docs_src/templates/partials/footer.hbs | 10 + .../docs_src/templates/partials/head.hbs | 30 + .../docs_src/templates/partials/header.hbs | 29 + .../templates/partials/home-carousel.hbs | 42 + .../templates/partials/home-features.hbs | 17 + .../docs_src/templates/partials/home-hero.hbs | 14 + .../templates/partials/home-teaser-text.hbs | 19 + .../templates/partials/javascripts.hbs | 3 + .../templates/partials/releated-docs.hbs | 0 .../templates/partials/sidenav-docs.hbs | 35 + .../docs_src/templates/partials/title.hbs | 7 + .../docs_src/templates/partials/vendors.hbs | 3 + .../js/OwlCarousel2-2.3.4/package-lock.json | 6169 +++++++++++++++++ resources/js/OwlCarousel2-2.3.4/package.json | 57 + .../src/img/ajax-loader.gif | Bin 0 -> 3208 bytes .../src/img/owl.video.play.png | Bin 0 -> 4976 bytes .../js/OwlCarousel2-2.3.4/src/js/.jscsrc | 47 + .../js/OwlCarousel2-2.3.4/src/js/.jshintrc | 13 + .../OwlCarousel2-2.3.4/src/js/owl.animate.js | 121 + .../src/js/owl.autoheight.js | 132 + .../OwlCarousel2-2.3.4/src/js/owl.autoplay.js | 233 + .../src/js/owl.autorefresh.js | 111 + .../OwlCarousel2-2.3.4/src/js/owl.carousel.js | 1750 +++++ .../js/OwlCarousel2-2.3.4/src/js/owl.hash.js | 122 + .../OwlCarousel2-2.3.4/src/js/owl.lazyload.js | 149 + .../src/js/owl.navigation.js | 406 ++ .../OwlCarousel2-2.3.4/src/js/owl.support.js | 83 + .../src/js/owl.support.modernizr.js | 66 + .../js/OwlCarousel2-2.3.4/src/js/owl.video.js | 327 + .../OwlCarousel2-2.3.4/src/scss/_animate.scss | 28 + .../src/scss/_autoheight.scss | 7 + .../js/OwlCarousel2-2.3.4/src/scss/_core.scss | 126 + .../src/scss/_lazyload.scss | 25 + .../src/scss/_theme.default.scss | 30 + .../src/scss/_theme.green.scss | 30 + .../OwlCarousel2-2.3.4/src/scss/_theme.scss | 64 + .../OwlCarousel2-2.3.4/src/scss/_video.scss | 53 + .../src/scss/owl.carousel.scss | 5 + .../src/scss/owl.theme.default.scss | 1 + .../src/scss/owl.theme.green.scss | 1 + .../js/OwlCarousel2-2.3.4/test/index.html | 32 + .../OwlCarousel2-2.3.4/test/unit/autoplay.js | 86 + .../js/OwlCarousel2-2.3.4/test/unit/core.js | 140 + resources/js/app.js | 57 + resources/sass/app.scss | 88 + resources/views/celebrity/show.blade.php | 66 +- resources/views/forum/index.blade.php | 2 +- resources/views/forum/thread.blade.php | 56 + resources/views/forum/topics/create.blade.php | 37 + resources/views/layouts/app.blade.php | 5 + resources/views/layouts/header.blade.php | 2 +- resources/views/layouts/rating.blade.php | 28 +- .../views/layouts/user_actions.blade.php | 23 + .../livewire/show-page/recommended.blade.php | 32 + .../livewire/show-page/similar.blade.php | 32 + .../livewire/show-page/tabs/cast.blade.php | 31 + .../livewire/show-page/tabs/crew.blade.php | 31 + .../livewire/show-page/tabs/details.blade.php | 55 + .../show-page/tabs/releases.blade.php | 3 + resources/views/movie/index.blade.php | 2 +- resources/views/movie/show.blade.php | 4 +- resources/views/profile/show.blade.php | 62 +- resources/views/show/index.blade.php | 67 + resources/views/show/show.blade.php | 168 + routes/web.php | 7 + 242 files changed, 38662 insertions(+), 99 deletions(-) create mode 100644 app/Http/Controllers/ShowController.php create mode 100644 app/Http/Requests/Forum/TopicRequest.php create mode 100644 app/Livewire/ShowPage/Recommended.php create mode 100644 app/Livewire/ShowPage/Similar.php create mode 100644 app/Livewire/ShowPage/Tabs/Cast.php create mode 100644 app/Livewire/ShowPage/Tabs/Crew.php create mode 100644 app/Livewire/ShowPage/Tabs/Details.php create mode 100644 app/Livewire/ShowPage/Tabs/Releases.php create mode 100644 public/img/imdb.png create mode 100644 public/img/tmdb.webp create mode 100644 public/img/tv_rage.png create mode 100644 public/img/tvdb.png create mode 100644 public/img/wikidata.png create mode 100644 resources/js/OwlCarousel2-2.3.4/.gitattributes create mode 100644 resources/js/OwlCarousel2-2.3.4/.gitignore create mode 100644 resources/js/OwlCarousel2-2.3.4/.travis.yml create mode 100644 resources/js/OwlCarousel2-2.3.4/CONTRIBUTING.md create mode 100644 resources/js/OwlCarousel2-2.3.4/Gruntfile.js create mode 100644 resources/js/OwlCarousel2-2.3.4/ISSUE_TEMPLATE.md create mode 100644 resources/js/OwlCarousel2-2.3.4/LICENSE create mode 100644 resources/js/OwlCarousel2-2.3.4/README.md create mode 100644 resources/js/OwlCarousel2-2.3.4/ROADMAP.md create mode 100644 resources/js/OwlCarousel2-2.3.4/_config.json create mode 100644 resources/js/OwlCarousel2-2.3.4/bower.json create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/LICENSE create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/README.md create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/ajax-loader.gif create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.carousel.css create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.carousel.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.theme.default.css create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.theme.default.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.theme.green.css create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.theme.green.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/assets/owl.video.play.png create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/owl.carousel.js create mode 100644 resources/js/OwlCarousel2-2.3.4/dist/owl.carousel.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/css/animate.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/css/docs.theme.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/bird_blue_32.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/download.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/feature-drag.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/feature-modern.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/feature-module.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/feature-options.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/feature-responsive.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/feature-zombie.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/owl-logo.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/img/twitter_25.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/js/app.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/js/foundation.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/README.md create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/ajax-loader.gif create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.carousel.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.carousel.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.theme.default.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.theme.default.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.theme.green.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.theme.green.min.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/assets/owl.video.play.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/owl.carousel.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/owlcarousel/owl.carousel.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/vendors/foundation.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/vendors/highlight.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/vendors/jquery.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/vendors/jquery.min.map create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/assets/vendors/jquery.mousewheel.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/animate.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/autoheight.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/autoplay.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/autowidth.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/basic.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/center.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/demos.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/events.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/lazyLoad.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/merge.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/mousewheel.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/responsive.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/rtl.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/stagepadding.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/test.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/urlhashnav.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/demos/video.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/api-classes.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/api-events.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/api-options.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/dev-buildin-plugins.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/dev-external.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/dev-plugin-api.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/dev-styles.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/started-faq.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/started-installation.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/started-welcome.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/support-changelog.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/support-contact.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/docs/support-contributing.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs/index.html create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/css/animate.css create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/bird_blue_32.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/download.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/feature-drag.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/feature-modern.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/feature-module.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/feature-options.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/feature-responsive.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/feature-zombie.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/owl-logo.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/img/twitter_25.png create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/js/app.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/js/foundation.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/scss/_settings.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/scss/custom.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/scss/demos.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/scss/docs.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/scss/docs.theme.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/scss/highlight.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/vendors/foundation.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/vendors/highlight.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/vendors/jquery.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/assets/vendors/jquery.min.map create mode 100755 resources/js/OwlCarousel2-2.3.4/docs_src/assets/vendors/jquery.mousewheel.min.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/data/classes.json create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/data/events.json create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/data/features.json create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/data/options.json create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/helpers/modulo.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/helpers/test.js create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/layouts/demos.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/layouts/docs.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/layouts/home.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/animate.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/autoheight.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/autoplay.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/autowidth.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/basic.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/center.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/demos.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/events.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/lazyLoad.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/merge.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/mousewheel.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/responsive.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/rtl.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/stagepadding.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/test.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/urlhashnav.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/demos/video.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/api-classes.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/api-events.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/api-options.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/dev-buildin-plugins.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/dev-external.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/dev-plugin-api.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/dev-styles.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/started-faq.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/started-installation.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/started-welcome.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/support-changelog.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/support-contact.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/docs/support-contributing.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/pages/index.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/footer.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/head.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/header.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/home-carousel.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/home-features.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/home-hero.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/home-teaser-text.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/javascripts.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/releated-docs.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/sidenav-docs.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/title.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/docs_src/templates/partials/vendors.hbs create mode 100644 resources/js/OwlCarousel2-2.3.4/package-lock.json create mode 100644 resources/js/OwlCarousel2-2.3.4/package.json create mode 100644 resources/js/OwlCarousel2-2.3.4/src/img/ajax-loader.gif create mode 100644 resources/js/OwlCarousel2-2.3.4/src/img/owl.video.play.png create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/.jscsrc create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/.jshintrc create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.animate.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.autoheight.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.autoplay.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.autorefresh.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.carousel.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.hash.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.lazyload.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.navigation.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.support.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.support.modernizr.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/js/owl.video.js create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_animate.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_autoheight.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_core.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_lazyload.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_theme.default.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_theme.green.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_theme.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/_video.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/owl.carousel.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/owl.theme.default.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/src/scss/owl.theme.green.scss create mode 100644 resources/js/OwlCarousel2-2.3.4/test/index.html create mode 100644 resources/js/OwlCarousel2-2.3.4/test/unit/autoplay.js create mode 100644 resources/js/OwlCarousel2-2.3.4/test/unit/core.js create mode 100644 resources/views/forum/thread.blade.php create mode 100644 resources/views/forum/topics/create.blade.php create mode 100644 resources/views/layouts/user_actions.blade.php create mode 100644 resources/views/livewire/show-page/recommended.blade.php create mode 100644 resources/views/livewire/show-page/similar.blade.php create mode 100644 resources/views/livewire/show-page/tabs/cast.blade.php create mode 100644 resources/views/livewire/show-page/tabs/crew.blade.php create mode 100644 resources/views/livewire/show-page/tabs/details.blade.php create mode 100644 resources/views/livewire/show-page/tabs/releases.blade.php create mode 100644 resources/views/show/index.blade.php create mode 100644 resources/views/show/show.blade.php diff --git a/app/Console/Commands/ItemProcessing/FetchItemDataCommand.php b/app/Console/Commands/ItemProcessing/FetchItemDataCommand.php index 8e58f3f..1b19766 100644 --- a/app/Console/Commands/ItemProcessing/FetchItemDataCommand.php +++ b/app/Console/Commands/ItemProcessing/FetchItemDataCommand.php @@ -6,6 +6,8 @@ use App\Models\ItemToFetch; use App\Models\ItemToFetchJobs; use App\Models\Movie; use App\Service\MediaProcessing\FactoryService; +use App\Service\MediaProcessing\MovieProcessingService; +use App\Service\MediaProcessing\ShowProcessingService; use Illuminate\Console\Command; class FetchItemDataCommand extends Command @@ -15,7 +17,7 @@ class FetchItemDataCommand extends Command * * @var string */ - protected $signature = 'processing:fetch-item-data {type=movie} {batch=50} {job=Details}'; + protected $signature = 'processing:fetch-item-data {type=movie} {batch=50} {job=Details} {tmdbId?}'; /** * The console command description. @@ -36,42 +38,47 @@ class FetchItemDataCommand extends Command */ public function handle() { + $this->info("Start"); + $type = $this->argument('type'); $batch = $this->argument('batch'); $job = $this->argument('job'); + $tmdbId = $this->argument('tmdbId'); - $items = $this->getBatch($type, $batch, $job); + $items = $this->getBatch($type, $batch, $job, $tmdbId); - $this->processItems($items, $job); + $this->info("Processing ".count($items)." items of type `{$type}`."); + + $this->processItems($items, $job, $type); + + $this->info("Fin."); } - private function getBatch(string $type, int $batch, string $job) + private function getBatch(string $type, int $batch, string $job, int $tmdbId = null) { - // if job <> Details the movie in movie table should exist - $query = ItemToFetch::whereHas('jobs', function($query) use ($job){ - return $query->where('jobs', '<>', null)->whereRaw('FIND_IN_SET(?, jobs)', [$job]); - })->with(['jobs']); - - if ($job !== ItemToFetchJobs::JOB_DETAILS) { - $query = $query->join('movies', 'movies.tmdb_id', '=', 'items_to_fetch.tmdb_id'); + switch ($type){ + case ItemToFetch::TYPE_MOVIE: + return MovieProcessingService::getBatch($batch, $job); + case ItemToFetch::TYPE_TV_SERIES: + return ShowProcessingService::getBatch($batch, $job, $tmdbId); } - - return $query - ->where('type', $type) - ->take($batch) - ->get(); } - private function processItems(\Illuminate\Database\Eloquent\Collection $items, $job) + private function processItems(\Illuminate\Database\Eloquent\Collection $items, $job, $type) { + $bar = $this->output->createProgressBar(count($items)); + foreach ($items as $item) { - $this->processItem($item, $job); + $this->processItem($item, $job, $type); + $bar->advance(); } + + $bar->finish(); } - private function processItem($item, $job) + private function processItem($item, $job, $type) { - $this->factoryService->process($item, $job); + $this->factoryService->process($item, $job, $type); } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index a577495..b0e5390 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -76,6 +76,7 @@ class RegisterController extends Controller $this->createMediaList('Collection', $user); $this->createMediaList('Watched', $user); $this->createMediaList('Liked', $user); + $this->createMediaList('Favourite', $user); return $user; } diff --git a/app/Http/Controllers/CelebrityController.php b/app/Http/Controllers/CelebrityController.php index c870412..b228ac5 100644 --- a/app/Http/Controllers/CelebrityController.php +++ b/app/Http/Controllers/CelebrityController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers; use App\Models\Person; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class CelebrityController extends Controller { @@ -18,6 +19,32 @@ class CelebrityController extends Controller { $celebrity = Person::where('slug', $slug)->first(); - return view('celebrity.show', compact('celebrity')); + // movies by job + $movies = DB::table('movies') + ->leftJoin('movie_cast', 'movie_cast.movie_id', '=', 'movies.id') + ->where('movie_cast.person_id', '=', $celebrity->id) + ->get(); + + // movies crew + + $moviesByDepartments = []; + + foreach ($movies as $movie) { + $moviesByDepartments[$movie->known_for_department][]= $movie; + } + + + $showsByDepartment = []; + + $shows = DB::table('shows') + ->leftJoin('show_cast', 'show_cast.show_id', '=', 'shows.id') + ->where('show_cast.person_id', '=', $celebrity->id) + ->get(); + + foreach ($shows as $show) { + $showsByDepartment[$show->known_for_department][]= $show; + } + + return view('celebrity.show', compact('celebrity', 'moviesByDepartments', 'showsByDepartment')); } } diff --git a/app/Http/Controllers/Forum/ThreadsController.php b/app/Http/Controllers/Forum/ThreadsController.php index 98de268..04de65f 100644 --- a/app/Http/Controllers/Forum/ThreadsController.php +++ b/app/Http/Controllers/Forum/ThreadsController.php @@ -3,12 +3,22 @@ namespace App\Http\Controllers\Forum; use App\Http\Controllers\Controller; +use App\Models\Forum\Category; +use App\Models\Forum\Thread; +use App\Models\Forum\Topic; use Illuminate\Http\Request; class ThreadsController extends Controller { - public function show(string $threadSlug) + public function show(string $categorySlug, string $threadSlug) { + $category = Category::where('slug', $categorySlug)->first(); + $thread = Thread::where('slug', $threadSlug)->first(); + $topics = Topic::where('category_id', $category->id) + ->where('thread_id', $thread->id) + ->paginate(15); + + return view('forum.thread', compact('category', 'thread', 'topics')); } } diff --git a/app/Http/Controllers/Forum/TopicsController.php b/app/Http/Controllers/Forum/TopicsController.php index e78c85b..1eb3f4d 100644 --- a/app/Http/Controllers/Forum/TopicsController.php +++ b/app/Http/Controllers/Forum/TopicsController.php @@ -3,9 +3,13 @@ namespace App\Http\Controllers\Forum; use App\Http\Controllers\Controller; +use App\Http\Requests\Forum\TopicRequest; use Illuminate\Http\Request; class TopicsController extends Controller { - // + public function create(TopicRequest $request) + { + return view('forum.topics.create'); + } } diff --git a/app/Http/Controllers/ShowController.php b/app/Http/Controllers/ShowController.php new file mode 100644 index 0000000..ead0bc7 --- /dev/null +++ b/app/Http/Controllers/ShowController.php @@ -0,0 +1,25 @@ +where('slug', $slug)->first(); + + $comments = []; + + return view('show.show', compact('show', 'comments')); + } +} diff --git a/app/Http/Requests/Forum/TopicRequest.php b/app/Http/Requests/Forum/TopicRequest.php new file mode 100644 index 0000000..936630c --- /dev/null +++ b/app/Http/Requests/Forum/TopicRequest.php @@ -0,0 +1,28 @@ +|string> + */ + public function rules(): array + { + return [ + // + ]; + } +} diff --git a/app/Livewire/ShowPage/Recommended.php b/app/Livewire/ShowPage/Recommended.php new file mode 100644 index 0000000..0159d54 --- /dev/null +++ b/app/Livewire/ShowPage/Recommended.php @@ -0,0 +1,24 @@ +recommendedShows = Show::whereIn('id', ShowRecommendation::where('show_id', $this->show->id)->pluck('recommended_show_id')) + ->get(); + } +} diff --git a/app/Livewire/ShowPage/Similar.php b/app/Livewire/ShowPage/Similar.php new file mode 100644 index 0000000..0a31528 --- /dev/null +++ b/app/Livewire/ShowPage/Similar.php @@ -0,0 +1,24 @@ +similarShows = Show::whereIn('id', ShowSimilar::where('show_id', $this->show->id)->pluck('similar_show_id')) + ->get(); + } +} diff --git a/app/Livewire/ShowPage/Tabs/Cast.php b/app/Livewire/ShowPage/Tabs/Cast.php new file mode 100644 index 0000000..209f5d0 --- /dev/null +++ b/app/Livewire/ShowPage/Tabs/Cast.php @@ -0,0 +1,36 @@ +show = Show::with('castList')->where('id', $this->show->id)->first(); + + $peopleByDepartment = []; + + foreach ($this->show->castList as $castMember) { + if (!isset($peopleByDepartment[$castMember->pivot->known_for_department])) { + $peopleByDepartment[$castMember->pivot->known_for_department] = []; + } + $peopleByDepartment[$castMember->pivot->known_for_department][] = [ + Person::find($castMember->pivot->person_id), + $castMember->pivot->character, + ]; + } + $this->peopleByDepartment = $peopleByDepartment; + } +} diff --git a/app/Livewire/ShowPage/Tabs/Crew.php b/app/Livewire/ShowPage/Tabs/Crew.php new file mode 100644 index 0000000..30429cf --- /dev/null +++ b/app/Livewire/ShowPage/Tabs/Crew.php @@ -0,0 +1,37 @@ +show = Show::with('castList')->where('id', $this->show->id)->first(); + + $peopleByDepartment = []; + + foreach ($this->show->crewList as $castMember) { + + if (!isset($peopleByDepartment[$castMember->pivot->department])) { + $peopleByDepartment[$castMember->pivot->department] = []; + } + $peopleByDepartment[$castMember->pivot->department][] = [ + Person::find($castMember->pivot->person_id), + $castMember->pivot->job, + ]; + } + $this->peopleByDepartment = $peopleByDepartment; + } +} diff --git a/app/Livewire/ShowPage/Tabs/Details.php b/app/Livewire/ShowPage/Tabs/Details.php new file mode 100644 index 0000000..732ebd2 --- /dev/null +++ b/app/Livewire/ShowPage/Tabs/Details.php @@ -0,0 +1,15 @@ + 'array', - ]; - } } diff --git a/app/Models/Show.php b/app/Models/Show.php index 1bc5dbd..0f9ef80 100644 --- a/app/Models/Show.php +++ b/app/Models/Show.php @@ -36,6 +36,44 @@ class Show extends Model 'vote_count', ]; + protected $casts = [ + 'first_air_date' => 'date', + 'last_air_date' => 'date', + 'languages' => 'array', + ]; + + public function wasListedBy(string $listSlug, User $user) + { + $mediaList = MediaList::where('slug', $listSlug)->where('user_id', $user->id)->first(); + + if ($mediaList) { + $mediaListItem = MediaListItem::where('media_list_id', $mediaList->id) + ->where('item_id', $this->id) + ->where('item_type', 'show') + ->first(); + + return !empty($mediaListItem); + } + + return false; + } + + public function ratingBy(User $user) + { + $rating = Rate::where('user_id', $user->id) + ->where('item_id', $this->id) + ->where('item_type', 'show') + ->first(); + + return $rating ? $rating->rate : null; + } + + public function externalIds() + { + return $this->hasOne(ExternalId::class, 'entity_id', 'id') + ->where('external_ids.entity_type', 'show'); + } + public function castList() { return $this->belongsToMany(Person::class, 'show_cast', 'show_id', 'person_id'); @@ -46,9 +84,27 @@ class Show extends Model return $this->belongsToMany(Person::class, 'show_crew', 'show_id', 'person_id'); } - public function images() + public function images(string $type = 'posters') { - return $this->belongsToMany(Image::class, 'show_images', 'show_id', 'image_id'); + if ($type === Image::TYPE_POSTER) { + return $this->belongsToMany(Image::class, 'show_images', 'show_id', 'image_id') + ->where('type', Image::TYPE_POSTER); + } + + return $this->belongsToMany(Image::class, 'show_images', 'show_id', 'image_id') + ->where('type', '=', Image::TYPE_BACKDROP); + } + + public function posters() + { + return $this->belongsToMany(Image::class, 'show_images', 'show_id', 'image_id') + ->where('type', Image::TYPE_POSTER); + } + + public function backdrops() + { + return $this->belongsToMany(Image::class, 'show_images', 'show_id', 'image_id') + ->where('type', '=', Image::TYPE_BACKDROP); } public function videos() diff --git a/app/Service/MediaProcessing/FactoryService.php b/app/Service/MediaProcessing/FactoryService.php index 8c12d3f..dde1a7c 100644 --- a/app/Service/MediaProcessing/FactoryService.php +++ b/app/Service/MediaProcessing/FactoryService.php @@ -17,9 +17,9 @@ class FactoryService $this->showProcessingService = $showProcessingService; } - public function process($item, string $job) + public function process($item, string $job, $type) { - switch ($item->type) { + switch ($type) { case ItemToFetch::TYPE_MOVIE: return $this->movieProcessingService->process($item, $job); case ItemToFetch::TYPE_TV_SERIES: diff --git a/app/Service/MediaProcessing/MovieProcessingService.php b/app/Service/MediaProcessing/MovieProcessingService.php index 85d3776..6ce0a5d 100644 --- a/app/Service/MediaProcessing/MovieProcessingService.php +++ b/app/Service/MediaProcessing/MovieProcessingService.php @@ -46,6 +46,29 @@ class MovieProcessingService implements ProcessingInterface $this->listApi = $listApi; } + public static function getBatch(int $batch, string $job) + { + if ($job === ItemToFetchJobs::JOB_DETAILS) { + return ItemToFetchJobs::leftJoin('movies', function ($join) { + $join->on('movies.tmdb_id', '=', 'item_to_fetch_jobs.tmdb_id'); + }) + ->whereRaw("FIND_IN_SET('".ItemToFetchJobs::JOB_DETAILS."', item_to_fetch_jobs.jobs)") + ->where('item_to_fetch_jobs.type', 'movies') + ->whereNull('movies.id') + ->take($batch) + ->get(); + } + + return ItemToFetchJobs::leftJoin('movies', function ($join) { + $join->on('movies.tmdb_id', '=', 'item_to_fetch_jobs.tmdb_id'); + }) + ->whereRaw("FIND_IN_SET('".$job."', item_to_fetch_jobs.jobs)") + ->where('item_to_fetch_jobs.type', 'tv_series') + ->whereNotNull('movies.id') + ->take($batch) + ->get(); + } + public function process($item, $job) { $methodName = "get".ucfirst($job); diff --git a/app/Service/MediaProcessing/ShowProcessingService.php b/app/Service/MediaProcessing/ShowProcessingService.php index c96a97f..25cecdc 100644 --- a/app/Service/MediaProcessing/ShowProcessingService.php +++ b/app/Service/MediaProcessing/ShowProcessingService.php @@ -26,6 +26,7 @@ use App\Models\Video; use App\Models\WatchProvider; use App\Service\TMDBApi\PersonApi; use App\Service\TMDBApi\ShowsApi; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; use function PHPUnit\Framework\containsIdentical; @@ -42,13 +43,40 @@ class ShowProcessingService implements ProcessingInterface $this->personApi = $personApi; } + public static function getBatch(int $batch, string $job, int $tmdbId = null) + { + $query = ItemToFetchJobs::leftJoin('shows', function ($join) { + $join->on('shows.tmdb_id', '=', 'item_to_fetch_jobs.tmdb_id'); + }) + ->select('item_to_fetch_jobs.*'); + + if ($tmdbId) { + $query = $query->where('item_to_fetch_jobs.tmdb_id', $tmdbId); + } + + if ($job === ItemToFetchJobs::JOB_DETAILS) { + return $query + ->whereRaw("FIND_IN_SET('".ItemToFetchJobs::JOB_DETAILS."', item_to_fetch_jobs.jobs)") + ->where('item_to_fetch_jobs.type', 'tv_series') + ->whereNull('shows.id') + ->take($batch) + ->get(); + } + + return $query + ->whereRaw("FIND_IN_SET('".$job."', item_to_fetch_jobs.jobs)") + ->where('item_to_fetch_jobs.type', 'tv_series') + ->whereNotNull('shows.id') + ->take($batch) + ->get(); + } + public function process($item, $job) { $methodName = "get".ucfirst($job); if (!method_exists($this, $methodName)) { - // @todo maybe raise an exception here - return; + throw new \Exception("No method named $methodName\n"); } $this->$methodName($item); @@ -62,10 +90,10 @@ class ShowProcessingService implements ProcessingInterface $show = Show::where('tmdb_id', $item->tmdb_id)->first(); if ($show) { - echo "+"; +// echo "+"; return; } - echo "."; +// echo "."; $tmdbShow['slug'] = Str::slug($tmdbShow['name'].'-'.$tmdbShow['tmdb_id']); $tmdbShow['first_air_date'] = $tmdbShow['first_air_date'] ? new \DateTime($tmdbShow['first_air_date']) : null; $tmdbShow['last_air_date'] = $tmdbShow['last_air_date'] ? new \DateTime($tmdbShow['last_air_date']) : null; @@ -140,11 +168,13 @@ class ShowProcessingService implements ProcessingInterface $tmdbCredits = $this->showsApi->getCredits($item->tmdb_id); if (empty($tmdbCredits)) { + echo "no credits\n"; return; } $show = Show::where('tmdb_id', $item->tmdb_id)->first(); + echo $item->tmdb_id."\n"; $this->processCast($show, $tmdbCredits['cast'] ?? []); $this->processCrew($show, $tmdbCredits['crew'] ?? []); @@ -177,7 +207,27 @@ class ShowProcessingService implements ProcessingInterface $externalIds['entity_id'] = $show->id; $externalIds['entity_type'] = ExternalId::TYPE_SHOW; + $externalId['imdb_id'] = $tmdbExternalIds['imdb_id'] ?? null; + $externalId['wikidata_id'] = $tmdbExternalIds['wikidata_id'] ?? null; + $externalId['facebook_id'] = $tmdbExternalIds['facebook_id'] ?? null; + $externalId['instagram_id'] = $tmdbExternalIds['instagram_id'] ?? null; + $externalId['twitter_id'] = $tmdbExternalIds['twitter_id'] ?? null; + $externalId['tvdb_id'] = $tmdbExternalIds['tvdb_id'] ?? null; + $externalId['freebase_id'] = $tmdbExternalIds['freebase_id'] ?? null; + $externalId['tvrage_id'] = $tmdbExternalIds['tvrage_id'] ?? null; + ExternalId::create($externalIds); + } else { + + $externalId->imdb_id = $tmdbExternalIds['imdb_id'] ?? null; + $externalId->wikidata_id = $tmdbExternalIds['wikidata_id'] ?? null; + $externalId->facebook_id = $tmdbExternalIds['facebook_id'] ?? null; + $externalId->instagram_id = $tmdbExternalIds['instagram_id'] ?? null; + $externalId->twitter_id = $tmdbExternalIds['twitter_id'] ?? null; + $externalId->tvdb_id = $tmdbExternalIds['tvdb_id'] ?? null; + $externalId->freebase_id = $tmdbExternalIds['freebase_id'] ?? null; + $externalId->tvrage_id = $tmdbExternalIds['tvrage_id'] ?? null; + $externalId->save(); } $this->removeElementFromRemainingJobs($item->tmdb_id, ItemToFetchJobs::JOB_EXTERNAL_IDS); @@ -250,12 +300,17 @@ class ShowProcessingService implements ProcessingInterface ]); } - if ($show->whereHas('videos', function ($query) use ($show) { - $query->where('show_id', $show->id); - })->exists()) { - return; - } else { - $show->videos()->attach($videoExists); + $videoIsAttached = DB::table('show_videos') + ->where('show_id', $show->id) + ->where('video_id', $videoExists->id) + ->first(); + + if (!$videoIsAttached) { + DB::table('show_videos') + ->insert([ + 'show_id' => $show->id, + 'video_id' => $videoExists->id + ]); } } @@ -282,12 +337,17 @@ class ShowProcessingService implements ProcessingInterface ]); } - if ($show->whereHas('keywords', function ($query) use ($existingKeyword) { - $query->where('tmdb_id', $existingKeyword->tmdb_id); - })->exists()) { - return; - } else { - $show->keywords()->attach($existingKeyword); + $keywordIsAttached = DB::table('show_keywords') + ->where('show_id', $show->id) + ->where('keyword_id', $existingKeyword->id) + ->first(); + + if (!$keywordIsAttached) { + DB::table('show_keywords') + ->insert([ + 'show_id' => $show->id, + 'keyword_id' => $existingKeyword->id, + ]); } } @@ -597,12 +657,25 @@ class ShowProcessingService implements ProcessingInterface private function removeElementFromRemainingJobs(int $tmdbId, string $job) { - $itemToFetchJobs = ItemToFetchJobs::where('tmdb_id', $tmdbId)->first(); + $itemToFetchJobs = ItemToFetchJobs::where('tmdb_id', $tmdbId) + ->where('type', 'tv_series') + ->first(); - $remainingJobs = $itemToFetchJobs->remaining_jobs; + if (!$itemToFetchJobs) { + echo "no job for ".$tmdbId."\n"; + return; + } + + $remainingJobs = $itemToFetchJobs->jobs; if (is_string($remainingJobs)) { - $remainingJobs = json_decode($remainingJobs, true); + $remainingJobs = explode(',', $remainingJobs); + } else if ($itemToFetchJobs->jobs == null) { + $this->removeItemToFetch($tmdbId); + return; + } else { + dd("Not string", $remainingJobs, $itemToFetchJobs); + return; } $remainingJobKey = array_search($job, $remainingJobs); @@ -610,20 +683,42 @@ class ShowProcessingService implements ProcessingInterface unset($remainingJobs[$remainingJobKey]); if (empty($remainingJobs)) { - $itemToFetchJobs->delete(); + $this->removeItemToFetch($tmdbId); + return; } - $itemToFetchJobs->remaining_jobs = $remainingJobs; + $itemToFetchJobs->jobs = implode(',', $remainingJobs); $itemToFetchJobs->save(); } + private function removeItemToFetch($tmdbId) + { + $itemToFetchJobs = ItemToFetchJobs::where('tmdb_id', $tmdbId) + ->where('type', 'tv_series') + ->first(); + + $itemToFetch = ItemToFetch::where('tmdb_id', $tmdbId) + ->where('type', 'tv_series') + ->first(); + + if ($itemToFetch) { + $itemToFetch->delete(); + } + + if ($itemToFetchJobs) { + $itemToFetchJobs->delete(); + } + } + private function processCast($show, array $credits) { - if (empty($credits)) { + if (empty($credits) || $show === null) { + echo "+"; return; } foreach ($credits as $castPerson) { + echo "Searching for person ".$castPerson['id']."\n"; $person = Person::where('tmdb_id', $castPerson['id'])->first(); if (!$person) { @@ -652,27 +747,33 @@ class ShowProcessingService implements ProcessingInterface ]); } + echo "Creating person ".$castPerson['id']."\n"; $person = Person::create($personData); } - if ($show->whereHas('castList', function ($query) use ($person) { - $query->where('tmdb_id', '=', $person->tmdb_id); - })->exists()) { - return; - } else { - $show->castList()->attach($person, [ - 'known_for_department' => $castPerson['known_for_department'], - 'character' => $castPerson['character'], - 'tmdb_cast_id' => $castPerson['cast_id'], - 'order' => $castPerson['order'], - ]); + $castExists = DB::table('show_cast') + ->where('show_id', $show->id) + ->where('person_id', $person->id) + ->first(); + + if (!$castExists) { + DB::table('show_cast') + ->insert([ + 'show_id' => $show->id, + 'person_id' => $person->id, + 'known_for_department' => trim($castPerson['known_for_department'], '"'), + 'character' => $castPerson['character'], + 'tmdb_cast_id' => $castPerson['credit_id'], + 'order' => $castPerson['order'], + ]); } } } private function processCrew($show, array $credits) { - if (empty($credits)) { + if (empty($credits) || $show === null) { + echo "+"; return; } @@ -708,17 +809,21 @@ class ShowProcessingService implements ProcessingInterface $person = Person::create($personData); } - if ($show->whereHas('crewList', function ($query) use ($person) { - $query->where('tmdb_id', '=', $person->tmdb_id); - })->exists()) { - return; - } else { - $show->crewList()->attach($person, [ - 'known_for_department' => json_encode($crewPerson['known_for_department']), - 'job' => $crewPerson['job'], - 'department' => $crewPerson['department'], - 'tmdb_cast_id' => $crewPerson['credit_id'], - ]); + $crewExists = DB::table('show_crew') + ->where('show_id', $show->id) + ->where('person_id', $person->id) + ->first(); + + if (!$crewExists) { + DB::table('show_crew') + ->insert([ + 'show_id' => $show->id, + 'person_id' => $person->id, + 'known_for_department' => trim($crewPerson['known_for_department'], '"'), + 'job' => $crewPerson['job'], + 'department' => $crewPerson['department'], + 'tmdb_cast_id' => $crewPerson['credit_id'], + ]); } } } diff --git a/database/migrations/2024_12_29_153704_create_item_to_fetch_jobs_table.php b/database/migrations/2024_12_29_153704_create_item_to_fetch_jobs_table.php index 9602448..8476654 100644 --- a/database/migrations/2024_12_29_153704_create_item_to_fetch_jobs_table.php +++ b/database/migrations/2024_12_29_153704_create_item_to_fetch_jobs_table.php @@ -16,7 +16,6 @@ return new class extends Migration $table->bigInteger('tmdb_id')->nullable(false); $table->bigInteger('item_id')->nullable(true); $table->string('type')->nullable(false); - $table->json('remaining_jobs')->default(null); $table->set('jobs', \App\Models\ItemToFetchJobs::JOBS)->default(null); $table->timestamps(); }); diff --git a/database/migrations/2025_01_27_191019_create_topics_table.php b/database/migrations/2025_01_27_191019_create_topics_table.php index fa97981..7b9be4e 100644 --- a/database/migrations/2025_01_27_191019_create_topics_table.php +++ b/database/migrations/2025_01_27_191019_create_topics_table.php @@ -16,6 +16,8 @@ return new class extends Migration $table->string('name'); $table->string('slug'); $table->enum('status', ['open', 'closed', 'sticky']); + $table->unsignedBigInteger('category_id'); + $table->unsignedBigInteger('thread_id'); $table->unsignedBigInteger('user_id'); $table->timestamps(); }); diff --git a/package-lock.json b/package-lock.json index defe277..afd2afb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,9 @@ "packages": { "": { "dependencies": { - "jquery": "^3.7.1" + "bs5-lightbox": "^1.8.3", + "jquery": "^3.7.1", + "owl-carousel": "^1.0.0" }, "devDependencies": { "@popperjs/core": "^2.11.6", @@ -892,7 +894,6 @@ "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "dev": true, "license": "MIT", "funding": { "type": "opencollective", @@ -1310,7 +1311,6 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", - "dev": true, "funding": [ { "type": "github", @@ -1382,6 +1382,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs5-lightbox": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/bs5-lightbox/-/bs5-lightbox-1.8.3.tgz", + "integrity": "sha512-fEIjplDAtWw17vi6dFeu7+Td52sk3qQ9FbOOVSpWM3nqio502vZKIA0Q0De9D9ah44BGd+zOKUsikRPlKE2hFg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/trvswgnr" + }, + "peerDependencies": { + "bootstrap": "^5.0.0" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -2287,6 +2299,12 @@ "node": ">= 6" } }, + "node_modules/owl-carousel": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/owl-carousel/-/owl-carousel-1.0.0.tgz", + "integrity": "sha512-xgOxxUqpSPM0dopWkcMri9MoGv8TrEDAnsc+6OYuHhO2x3YpsEKDW2fJomPDOA6KkSTa3utLvgP+irVwAXSGog==", + "license": "ISC" + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", diff --git a/package.json b/package.json index 8725fd7..6ea92dc 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "vite": "^6.0" }, "dependencies": { - "jquery": "^3.7.1" + "bs5-lightbox": "^1.8.3", + "jquery": "^3.7.1", + "owl-carousel": "^1.0.0" } } diff --git a/public/img/imdb.png b/public/img/imdb.png new file mode 100644 index 0000000000000000000000000000000000000000..d1f25261b3be3696381590f112e70ed01d42bc2d GIT binary patch literal 10602 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 literal 0 HcmV?d00001 diff --git a/public/img/tmdb.webp b/public/img/tmdb.webp new file mode 100644 index 0000000000000000000000000000000000000000..7e8f1530c90b2948b58fd2fe89b91e77be292cea GIT binary patch literal 2104 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 literal 0 HcmV?d00001 diff --git a/public/img/tv_rage.png b/public/img/tv_rage.png new file mode 100644 index 0000000000000000000000000000000000000000..61f41874947abcf09aa8d9165cbf871846557864 GIT binary patch literal 11505 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 X;h_9-1R>8Z00000NkvXXu0mjf<>=qo literal 0 HcmV?d00001 diff --git a/public/img/tvdb.png b/public/img/tvdb.png new file mode 100644 index 0000000000000000000000000000000000000000..1d751483b61b06e73075e2e00c952a91e9ed171f GIT binary patch literal 13876 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 literal 0 HcmV?d00001 diff --git a/public/img/wikidata.png b/public/img/wikidata.png new file mode 100644 index 0000000000000000000000000000000000000000..290f8247c86e680e1f8cadc433906c56cf3d5c4d GIT binary patch literal 1393 zcmd5+YfMvT82;K)s4x)~g4EzjhN!DzVZsIzDF%c_X;8rn!Ymgh3=q_cOeWT%f@8`i zPSG*b#K@p(k;|}wiG;$K2%{(%0FJGR# zc`qmMW0$%zT>$_~d2!Ku0HBa1kT7Uu9PZujP9~?UsQ4%V8Y|r#X>_t@WyI}?2jENq z0HO;3pyWt23&1H30FVHH@M-|O3u@YSZzUhQldvl>h9vwqrcWPVXla6KsD zCQy{H*>Ef3z%h%>2-{5gF;xLM1IAO&I)Ir!B1VJpK4!gzn)`}qn zL9&SPLy4$Phs{B=Rh8!MF2dn3G|C`J4Q{iI>6GW1QYzYVhcrD`+K=5~Kqd`r zH;*TipPV&3l9elRxS^qe z$z=NZ`ME2nbfmvb;U4~8if8si#j4h_mxC~A#a~c9mUZ8!Z15mil=Pjk(V(2}8%H)S zLSB4~ib%4y=b9VUSMJ~I8Rf~HrlfkGoSWaIl zuBHjPYfk>6ev0%+b>i3R*U-sNYN20mLx#;fsr0x0D=lFoNxW;{?q7Y}e1g{z3YmEE z6Tn<0pE}&mDikGCh_i01LwAf^>e?bopRBEuviY>Ssa=VAGH))RIC%&Hxb=Q@%O#By zU!|_(X79YHf3>2sRi8ZoTDE*&<@*rieLVib+$g=%AZW?@$v-!L9e4lfGo2l4M6XmU z#*4Ek>lc=VgMvr-=L*Zv^QLLn@%Lz;H1_3HN`WIfJS@zq;L{@i=9hOt&5|8il#fnt z!^+&eDS@f{W%3hVf{pU-p|=M?fQ+8%B5yP%7gijjuB>3^-khMyBW@MCh}x|$p5gbv z^Brq4k%BN#DIUrI`?fwK(zJU;NrNwF`yyS6mZzkf?g1);CHh~6&P9+=;$>l~1XK6t z-C>&cL$B6YXW%?l`-G;lT^5>37^-1oS^u`HRO5zKXPs3OH|O6COmUK1LLyY-Nuoy8 ziu_*E=Mbk5>XsX;n{ue@^XeZ>CR0a|h=)F+8#6-FT`!3~tN5sII~eu-66vqLpw~Oi zLi}a65t@>jqAp(82pawWbcf4Gc!2pPo$AR37waQ;ha^=yd*o5034;E|+T>jOd;-}0 zABWCZ8wS?$lHfM@>sDFY`*t_+*qB5=EO|mM@>*fc0bypE@JM*Zi6dkJ!JOcrO`MQT x!9j^ZoN!KPI46wFAq!6On`H8={Y{XUpP7C1vws(`JJcdl0C+L{XxVmw_;=RVeV+gT literal 0 HcmV?d00001 diff --git a/resources/js/OwlCarousel2-2.3.4/.gitattributes b/resources/js/OwlCarousel2-2.3.4/.gitattributes new file mode 100644 index 0000000..1de3646 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/.gitattributes @@ -0,0 +1,5 @@ +* text eol=lf + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary diff --git a/resources/js/OwlCarousel2-2.3.4/.gitignore b/resources/js/OwlCarousel2-2.3.4/.gitignore new file mode 100644 index 0000000..786d60e --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/.gitignore @@ -0,0 +1,18 @@ +*.iml +.sass-cache +.bowerrc +.idea +/bower_components +/node_modules +*.sublime* +*.zip +/jscs.report.txt + +.DS_Store +*/.DS_Store +.DS_Store? +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +.grunt diff --git a/resources/js/OwlCarousel2-2.3.4/.travis.yml b/resources/js/OwlCarousel2-2.3.4/.travis.yml new file mode 100644 index 0000000..9ffb730 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/.travis.yml @@ -0,0 +1,14 @@ +language: node_js +node_js: + - 'lts/*' + +before_install: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + +before_script: + - npm install -g bower grunt-cli + - bower install + +script: + - grunt test diff --git a/resources/js/OwlCarousel2-2.3.4/CONTRIBUTING.md b/resources/js/OwlCarousel2-2.3.4/CONTRIBUTING.md new file mode 100644 index 0000000..62c0cd1 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/CONTRIBUTING.md @@ -0,0 +1,88 @@ +## Contributing + +The [issue tracker](https://github.com/OwlCarousel2/OwlCarousel2/issues) is the preferred channel for bug reports, feature requests, and submitting pull requests. + +**Please do not use the issue tracker for personal support requests. Stack Overflow ([`owl-carousel`](https://stackoverflow.com/questions/tagged/owl-carousel)) is a better place to get help.** + +### Bug reports + +A bug is a **demonstrable, reproducible problem** that is caused by the code in the repository. Good bug reports are extremely helpful, so thanks! + +Guidelines for bug reports: + + 1. Use the GitHub issue search — check if the issue has already been reported. + + 2. Check if the issue has been fixed — try to reproduce it using the latest `develop` branch in the repository. + + 3. Isolate the problem - you NEED to provide a live example — ideally also create a reduced test case. This [CodePen](https://codepen.io/anon/pen/prvbMp), [JSFiddle](https://jsfiddle.net/h8x8bvn9/2/) and [JS Bin](https://jsbin.com/bojonaceve/2/edit?html,js,output) are helpful templates you can fork or clone. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the browser/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> `` - a link to the reduced test case +> +> Any other information you want to share that is relevant to the issue being reported. This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits). + +### Feature requests + +Feature requests are welcome, but please take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. + +To get approval for your feature request, please create an issue on the issue tracker with as much detail and context as possible. We'll take a look at it and then [hopefully] apply the "[approved for development](https://github.com/OwlCarousel2/OwlCarousel2/labels/approved%20for%20development)" tag so someone can get to work on it! + +### Pull requests + +Good pull requests are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. + +Adhering to the following process is the best way to get your work included in the project: + + 1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: + + ```bash + git clone https://github.com//OwlCarousel2.git + cd OwlCarousel2 + git remote add upstream https://github.com/OwlCarousel2/OwlCarousel2.git + ``` + + 2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout develop + git pull [--rebase] upstream develop + ``` + + 3. Create a new topic branch (off the main project `develop` branch) to contain your feature, change, or fix: + + ```bash + git checkout -b + ``` + + 4. Build the distribution before committing to ensure your changes follow the coding standards and all build files are up to date. + + ```bash + grunt dist + ``` + + 5. Commit your changes in logical chunks. Please adhere to these [guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. + + 6. Locally merge (or rebase) the upstream development branch into your topic branch: + + ```bash + git pull [--rebase] upstream develop + ``` + + 7. Push your topic branch up to your fork: + + ```bash + git push origin + ``` + + 8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `develop` branch. + +**By submitting a patch, you agree to allow the project owner to license your work under the terms of the [MIT License](LICENSE).** diff --git a/resources/js/OwlCarousel2-2.3.4/Gruntfile.js b/resources/js/OwlCarousel2-2.3.4/Gruntfile.js new file mode 100644 index 0000000..79c5fa4 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/Gruntfile.js @@ -0,0 +1,320 @@ +/** + * Owl Carousel + * + * Bartosz Wojciechowski + * + * Copyright (c) 2014 + * Licensed under the MIT license. + */ +module.exports = function(grunt) { + + require('load-grunt-tasks')(grunt); + + grunt + .initConfig({ + pkg: grunt.file.readJSON('package.json'), + app: grunt.file.readJSON('_config.json'), + banner: '/**\n' + ' * Owl Carousel v<%= pkg.version %>\n' + + ' * Copyright 2013-<%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' + + ' * Licensed under: <%= pkg.license %>\n' + ' */\n', + + // assemble + assemble: { + options: { + flatten: false, + expand: true, + production: false, + assets: '<%= app.docs.dest %>/assets', + postprocess: require('pretty'), + + // metadata + pkg: '<%= pkg %>', + app: '<%= app %>', + data: [ '<%= app.docs.src %>/data/*.{json,yml}' ], + + // templates + partials: '<%= app.docs.templates %>/partials/*.hbs', + layoutdir: '<%= app.docs.layouts %>/', + + // extensions + helpers: '<%= app.docs.src %>/helpers/*.js' + }, + index: { + options: { + layout: 'home.hbs' + }, + files: [ { + expand: true, + cwd: '<%= app.docs.pages %>/', + src: '*.hbs', + dest: '<%= app.docs.dest %>/' + } ] + }, + demos: { + options: { + layout: 'demos.hbs' + }, + files: [ { + expand: true, + cwd: '<%= app.docs.pages %>/demos/', + src: '*.hbs', + dest: '<%= app.docs.dest %>/demos' + } ] + }, + docs: { + options: { + layout: 'docs.hbs' + }, + files: [ { + expand: true, + cwd: '<%= app.docs.pages %>/docs/', + src: '*.hbs', + dest: '<%= app.docs.dest %>/docs' + } ] + } + }, + + // clean + clean: { + docs: [ '<%= app.docs.dest %>' ], + dist: [ 'dist' ] + }, + + // sass + sass: { + docs: { + options: { + outputStyle: 'compressed', + includePaths: [ '<%= app.docs.src %>/assets/scss/', 'node_modules/foundation-sites/scss' ] + }, + files: { + '<%= app.docs.dest %>/assets/css/docs.theme.min.css': '<%= app.docs.src %>/assets/scss/docs.theme.scss' + } + }, + dist: { + options: { + outputStyle: 'nested' + }, + files: { + 'dist/assets/<%= pkg.name %>.css': 'src/scss/<%= pkg.name %>.scss', + 'dist/assets/owl.theme.default.css': 'src/scss/owl.theme.default.scss', + 'dist/assets/owl.theme.green.css': 'src/scss/owl.theme.green.scss' + } + } + }, + + autoprefixer: { + options: { + browsers: [ 'last 2 versions', 'ie 7', 'ie 8', 'ie 9', 'ie 10', 'ie 11' ] + }, + dist: { + files: { + 'dist/assets/<%= pkg.name %>.css': 'dist/assets/<%= pkg.name %>.css', + 'dist/assets/owl.theme.default.css': 'dist/assets/owl.theme.default.css', + 'dist/assets/owl.theme.green.css': 'dist/assets/owl.theme.green.css' + } + } + }, + + concat: { + dist: { + files: { + 'dist/<%= pkg.name %>.js': '<%= app.src.scripts %>' + } + } + }, + + cssmin: { + dist: { + files: { + 'dist/assets/<%= pkg.name %>.min.css': 'dist/assets/<%= pkg.name %>.css', + 'dist/assets/owl.theme.default.min.css': 'dist/assets/owl.theme.default.css', + 'dist/assets/owl.theme.green.min.css': 'dist/assets/owl.theme.green.css' + } + } + }, + + jshint: { + options: { + jshintrc: 'src/js/.jshintrc' + }, + dist: { + src: [ '<%= app.src.scripts %>', 'Gruntfile.js' ] + } + }, + + qunit: { + options: { + timeout: 10000 + }, + dist: [ 'test/index.html' ] + }, + + jscs: { + options: { + config: 'src/js/.jscsrc', + reporter: 'text.js', + reporterOutput: 'jscs.report.txt' + }, + dist: { + src: [ '<%= app.src.scripts %>', 'Gruntfile.js' ] + } + }, + + usebanner: { + dist: { + options: { + banner: '<%= banner %>', + linebreak: false + }, + files: { + src: [ + 'dist/<%= pkg.name %>.js', + 'dist/assets/*.css' + ] + } + } + }, + + uglify: { + options: { + banner: '<%= banner %>' + }, + dist: { + files: { + 'dist/<%= pkg.name %>.min.js': 'dist/<%= pkg.name %>.js' + } + } + }, + + // copy + copy: { + distImages: { + expand: true, + flatten: true, + cwd: 'src/', + src: [ 'img/*.*' ], + dest: 'dist/assets' + }, + + distToDocs: { + expand: true, + cwd: 'dist/', + src: [ '**/*.*' ], + dest: '<%= app.docs.dest %>/assets/owlcarousel' + }, + + srcToDocs: { + expand: true, + cwd: 'src/js', + src: [ '**/*.js' ], + dest: '<%= app.docs.dest %>/assets/owlcarousel/src' + }, + + docsAssets: { + expand: true, + cwd: '<%= app.docs.src %>/assets/', + src: [ 'css/*.css', 'vendors/*.js', 'vendors/*.map', 'img/*.*', 'js/*.*' ], + dest: '<%= app.docs.dest %>/assets/' + }, + + readme: { + files: [ { + 'dist/LICENSE': 'LICENSE', + 'dist/README.md': 'README.md' + } ] + } + }, + + // connect + connect: { + options: { + port: 9600, + open: true, + livereload: true, + hostname: 'localhost' + }, + docs: { + options: { + base: "<%= app.docs.dest %>" + } + } + }, + + // watch + watch: { + options: { + livereload: true + }, + templatesDocs: { + files: [ '<%= app.docs.templates %>/**/*.hbs' ], + tasks: [ 'assemble' ] + }, + sassDocs: { + files: [ '<%= app.docs.src %>/assets/**/*.scss' ], + tasks: [ 'sass:docs' ] + }, + sass: { + files: [ 'src/**/*.scss' ], + tasks: [ 'sass:dist', 'cssmin:dist', 'usebanner:dist', 'copy:distToDocs' ] + }, + jsDocs: { + files: [ '<%= app.docs.src %>/assets/**/*.js' ], + tasks: [ 'copy:docsAssets' ] + }, + js: { + files: [ 'src/**/*.js' ], + tasks: [ 'jscs:dist', 'jshint:dist', 'qunit:dist', 'concat:dist', 'uglify:dist', 'usebanner:dist', 'copy:distToDocs', 'copy:srcToDocs' ] + }, + helpersDocs: { + files: [ '<%= app.docs.src %>/helpers/*.js' ], + tasks: [ 'assemble' ] + }, + test: { + files: [ 'test/*.html', 'test/unit/*.js' ], + tasks: [ 'qunit:dist' ] + } + }, + + // compress zip + compress: { + zip: { + options: { + archive: 'docs/download/owl.carousel.<%= pkg.version %>.zip' + }, + files: [ { + expand: true, + cwd: 'dist/', + src: [ '**' ], + dest: 'owl.carousel.<%= pkg.version %>' + } ] + } + }, + + // publish to github pages + 'gh-pages': { + options: { + base: 'docs' + }, + src: '**/*' + } + }); + + grunt.loadNpmTasks('assemble'); + + // tasks + grunt.registerTask('dist', [ 'clean:dist', 'sass:dist', 'autoprefixer', 'concat:dist', 'cssmin:dist', 'copy:distImages', 'usebanner:dist', 'uglify:dist', 'copy:readme' ]); + + grunt.registerTask('docs', [ 'dist', 'clean:docs', 'assemble', 'sass:docs', 'copy:docsAssets', 'copy:distToDocs', 'zip' ]); + + grunt.registerTask('test', [ 'jshint:dist', 'qunit:dist', 'jscs:dist' ]); + + grunt.registerTask('default', [ 'dist', 'docs', 'test' ]); + + grunt.registerTask('serve', [ 'connect:docs', 'watch' ]); + + grunt.registerTask('zip', [ 'compress' ]); + + grunt.registerTask('deploy', [ 'docs', 'gh-pages' ]); + +}; diff --git a/resources/js/OwlCarousel2-2.3.4/ISSUE_TEMPLATE.md b/resources/js/OwlCarousel2-2.3.4/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..c50fbaa --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/ISSUE_TEMPLATE.md @@ -0,0 +1,14 @@ +### A summary of the issue and the browser/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug.> +1. This is the first step +2. This is the second step +3. Further steps, etc. + +_____________ +### `` - a link to the reduced test case. You can use one of the following services: +- https://codepen.io/anon/pen/prvbMp +- https://jsfiddle.net/h8x8bvn9/2/) +- https://jsbin.com/bojonaceve/2/edit?html,js,output + +_____________ +### Any other information you want to share that is relevant to the issue being reported. +This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits). diff --git a/resources/js/OwlCarousel2-2.3.4/LICENSE b/resources/js/OwlCarousel2-2.3.4/LICENSE new file mode 100644 index 0000000..052211d --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2014 Owl +Modified work Copyright 2016-2018 David Deutsch + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/resources/js/OwlCarousel2-2.3.4/README.md b/resources/js/OwlCarousel2-2.3.4/README.md new file mode 100644 index 0000000..e912df2 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/README.md @@ -0,0 +1,122 @@ +# Owl Carousel 2 + +Touch enabled [jQuery](https://jquery.com/) plugin that lets you create a beautiful, responsive carousel slider. **To get started, check out https://owlcarousel2.github.io/OwlCarousel2/.** + +**Notice:** The old Owl Carousel site (owlgraphic [dot] com) is no longer in use. Please delete all references to this in bookmarks and your own products' documentation as it's being used for malicious purposes. + +## Quick start + +### Install + +This package can be installed with: + +- [npm](https://www.npmjs.com/package/owl.carousel): `npm install --save owl.carousel` or `yarn add owl.carousel jquery` +- [bower](http://bower.io/search/?q=owl.carousel): `bower install --save owl.carousel` + +Or download the [latest release](https://github.com/OwlCarousel2/OwlCarousel2/releases). + +### Load + +#### Webpack + +Add jQuery via the "webpack.ProvidePlugin" to your webpack configuration: + + const webpack = require('webpack'); + + //... + plugins: [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery' + }), + ], + //... + +Load the required stylesheet and JS: + +```js +import 'owl.carousel/dist/assets/owl.carousel.css'; +import 'owl.carousel'; +``` + +#### Static HTML + +Put the required stylesheet at the [top](https://developer.yahoo.com/performance/rules.html#css_top) of your markup: + +```html + +``` + +```html + +``` + +**NOTE:** If you want to use the default navigation styles, you will also need to include `owl.theme.default.css`. + + +Put the script at the [bottom](https://developer.yahoo.com/performance/rules.html#js_bottom) of your markup right after jQuery: + +```html + + +``` + +```html + + +``` + +### Usage + +Wrap your items (`div`, `a`, `img`, `span`, `li` etc.) with a container element (`div`, `ul` etc.). Only the class `owl-carousel` is mandatory to apply proper styles: + +```html + +``` +**NOTE:** The `owl-theme` class is optional, but without it, you will need to style navigation features on your own. + + +Call the [plugin](https://learn.jquery.com/plugins/) function and your carousel is ready. + +```javascript +$(document).ready(function(){ + $('.owl-carousel').owlCarousel(); +}); +``` + +## Documentation + +The documentation, included in this repo in the root directory, is built with [Assemble](http://assemble.io/) and publicly available at https://owlcarousel2.github.io/OwlCarousel2/. The documentation may also be run locally. + +## Building + +This package comes with [Grunt](http://gruntjs.com/) and [Bower](http://bower.io/). The following tasks are available: + + * `default` compiles the CSS and JS into `/dist` and builds the doc. + * `dist` compiles the CSS and JS into `/dist` only. + * `watch` watches source files and builds them automatically whenever you save. + * `test` runs [JSHint](http://www.jshint.com/) and [QUnit](http://qunitjs.com/) tests headlessly in [PhantomJS](http://phantomjs.org/). + +To define which plugins are build into the distribution just edit `/_config.json` to fit your needs. + +## Contributing + +Please read [CONTRIBUTING.md](CONTRIBUTING.md). + +## Roadmap + +Please make sure to check out our [Roadmap Discussion](https://github.com/OwlCarousel2/OwlCarousel2/issues/1756). + + +## License + +The code and the documentation are released under the [MIT License](LICENSE). diff --git a/resources/js/OwlCarousel2-2.3.4/ROADMAP.md b/resources/js/OwlCarousel2-2.3.4/ROADMAP.md new file mode 100644 index 0000000..2d3a51f --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/ROADMAP.md @@ -0,0 +1,57 @@ +# OwlCarousel 2 Roadmap + +You can discuss the roadmap here: [#1756](https://github.com/OwlCarousel2/OwlCarousel2/issues/1756). + +## 2.3 - bugfixes, repo migration, minor features - current version + + - [x] clean up contributor guides + - [x] Work through a bunch of PRs + - [x] Various spelling and code style fixes: #1785, #1858, #1856, #1814, #1876, #1838, #1424 + - [x] [#1883](https://github.com/OwlCarousel2/OwlCarousel2/pull/1883) Fix infinite loop + - [x] [#1900](https://github.com/OwlCarousel2/OwlCarousel2/pull/1900) Add repository info to package.json + - [x] [#1770](https://github.com/OwlCarousel2/OwlCarousel2/pull/1770) Allow package file to expose CSS + - [x] [#1077](https://github.com/OwlCarousel2/OwlCarousel2/pull/1077) .center class hangs around when responsive options + - [x] [#1978](https://github.com/OwlCarousel2/OwlCarousel2/pull/1978) - Fix empty child auto width + - [x] [#1942](https://github.com/OwlCarousel2/OwlCarousel2/pull/1942) - Improving autoplay behavior + - [x] [#1915](https://github.com/OwlCarousel2/OwlCarousel2/pull/1915) - Fixing: [#1750](https://github.com/OwlCarousel2/OwlCarousel2/issues/1750) Passive event listeners, chrome and touch events + - [x] [#1704](https://github.com/OwlCarousel2/OwlCarousel2/issues/1704) - viewport width detection + - [ ] [#1717](https://github.com/OwlCarousel2/OwlCarousel2/issues/1717) - keyboard control + - [ ] update progress in [#1538](https://github.com/OwlCarousel2/OwlCarousel2/issues/1538) + +## 2.4 - finish up build pipeline, docs + + - [ ] move repo to company account (https://github.com/medienpark) + - [ ] [#1330](https://github.com/OwlCarousel2/OwlCarousel2/issues/1330) - finish moving to gulp + - [ ] ditto for moving to assemble for docs + - [ ] [#1666](https://github.com/OwlCarousel2/OwlCarousel2/issues/1666) - RTL center mode + - [ ] [#1613](https://github.com/OwlCarousel2/OwlCarousel2/issues/1613) - generic plugin integration + - [ ] [#1602](https://github.com/OwlCarousel2/OwlCarousel2/issues/1602) - CSS transitions fail except for default + +## 2.5 - cloning & worker cleanup + + - [ ] worker cleanup + - [ ] clone computation fix (and provide consistent access to slides) + - [ ] [#1575](https://github.com/OwlCarousel2/OwlCarousel2/issues/1575) & [#1621](https://github.com/OwlCarousel2/OwlCarousel2/issues/1621) - AutoHeight fixes + - [ ] [#1511](https://github.com/OwlCarousel2/OwlCarousel2/issues/1511) - do not disable nav when center = true & length == items + +## 2.6 - cleanup, code style, repo cleanup + + - [ ] clean up code ToDos + - [ ] fix code style + - [ ] check whether we want to support velocity.js (at least optionally) + - [ ] close not-yet-tagged issues older than 8 month + - [ ] [#1518](https://github.com/OwlCarousel2/OwlCarousel2/issues/1518) - slide change event issues (not cancelling events etc.) + - [ ] [#1563](https://github.com/OwlCarousel2/OwlCarousel2/issues/1563) - slide offset on last if loop = false + - [ ] [#1633](https://github.com/OwlCarousel2/OwlCarousel2/issues/1633) & [#1627](https://github.com/OwlCarousel2/OwlCarousel2/issues/1627) - (merged items) swipe/autoplay (mostly testing whether the worker/clone fixes in 2.5 solved this) + +## 2.7 - bugfixes & final, "LTS" 2.x release + + - [ ] [#1647](https://github.com/OwlCarousel2/OwlCarousel2/issues/1647) - 1px from prev. slide on current + - [ ] [#1523](https://github.com/OwlCarousel2/OwlCarousel2/issues/1523) - autoplay vs. video autoplay issue + - [ ] [#1343](https://github.com/OwlCarousel2/OwlCarousel2/issues/1343) - timeout per slide + +## 3.0 - Typescript, additional plugins, breaking changes + + - [ ] TypeScript refactoring + - [ ] remove css-mimicking settings (such as margins) and use CSS instead + - [ ] overlay plugin (to support overlay transitions etc.) diff --git a/resources/js/OwlCarousel2-2.3.4/_config.json b/resources/js/OwlCarousel2-2.3.4/_config.json new file mode 100644 index 0000000..49f9f59 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/_config.json @@ -0,0 +1,30 @@ +{ + "docs":{ + "src": "docs_src", + "dest": "docs", + "templates":"<%= app.docs.src %>/templates", + "pages": "<%= app.docs.templates %>/pages", + "layouts": "<%= app.docs.templates %>/layouts" + }, + + "src":{ + "dist": "dist", + + "scripts": [ + "src/js/owl.carousel.js", + "src/js/owl.autorefresh.js", + "src/js/owl.lazyload.js", + "src/js/owl.autoheight.js", + "src/js/owl.video.js", + "src/js/owl.animate.js", + "src/js/owl.autoplay.js", + "src/js/owl.navigation.js", + "src/js/owl.hash.js", + "src/js/owl.support.js" + ] + }, + + "title": "Owl Carousel", + "download": "https://github.com/OwlCarousel2/OwlCarousel2/archive/master.zip", + "donate": "https://www.paypal.com" +} diff --git a/resources/js/OwlCarousel2-2.3.4/bower.json b/resources/js/OwlCarousel2-2.3.4/bower.json new file mode 100644 index 0000000..394d733 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/bower.json @@ -0,0 +1,13 @@ +{ + "name": "owl.carousel", + "version": "2.3.4", + "main": [ + "dist/owl.carousel.js", + "dist/assets/owl.carousel.css", + "dist/assets/owl.theme.default.css" + ], + "ignore": [], + "dependencies": { + "jquery": ">= 1.8.3" + } +} diff --git a/resources/js/OwlCarousel2-2.3.4/dist/LICENSE b/resources/js/OwlCarousel2-2.3.4/dist/LICENSE new file mode 100644 index 0000000..052211d --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/dist/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2014 Owl +Modified work Copyright 2016-2018 David Deutsch + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/resources/js/OwlCarousel2-2.3.4/dist/README.md b/resources/js/OwlCarousel2-2.3.4/dist/README.md new file mode 100644 index 0000000..e912df2 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/dist/README.md @@ -0,0 +1,122 @@ +# Owl Carousel 2 + +Touch enabled [jQuery](https://jquery.com/) plugin that lets you create a beautiful, responsive carousel slider. **To get started, check out https://owlcarousel2.github.io/OwlCarousel2/.** + +**Notice:** The old Owl Carousel site (owlgraphic [dot] com) is no longer in use. Please delete all references to this in bookmarks and your own products' documentation as it's being used for malicious purposes. + +## Quick start + +### Install + +This package can be installed with: + +- [npm](https://www.npmjs.com/package/owl.carousel): `npm install --save owl.carousel` or `yarn add owl.carousel jquery` +- [bower](http://bower.io/search/?q=owl.carousel): `bower install --save owl.carousel` + +Or download the [latest release](https://github.com/OwlCarousel2/OwlCarousel2/releases). + +### Load + +#### Webpack + +Add jQuery via the "webpack.ProvidePlugin" to your webpack configuration: + + const webpack = require('webpack'); + + //... + plugins: [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + 'window.jQuery': 'jquery' + }), + ], + //... + +Load the required stylesheet and JS: + +```js +import 'owl.carousel/dist/assets/owl.carousel.css'; +import 'owl.carousel'; +``` + +#### Static HTML + +Put the required stylesheet at the [top](https://developer.yahoo.com/performance/rules.html#css_top) of your markup: + +```html + +``` + +```html + +``` + +**NOTE:** If you want to use the default navigation styles, you will also need to include `owl.theme.default.css`. + + +Put the script at the [bottom](https://developer.yahoo.com/performance/rules.html#js_bottom) of your markup right after jQuery: + +```html + + +``` + +```html + + +``` + +### Usage + +Wrap your items (`div`, `a`, `img`, `span`, `li` etc.) with a container element (`div`, `ul` etc.). Only the class `owl-carousel` is mandatory to apply proper styles: + +```html + +``` +**NOTE:** The `owl-theme` class is optional, but without it, you will need to style navigation features on your own. + + +Call the [plugin](https://learn.jquery.com/plugins/) function and your carousel is ready. + +```javascript +$(document).ready(function(){ + $('.owl-carousel').owlCarousel(); +}); +``` + +## Documentation + +The documentation, included in this repo in the root directory, is built with [Assemble](http://assemble.io/) and publicly available at https://owlcarousel2.github.io/OwlCarousel2/. The documentation may also be run locally. + +## Building + +This package comes with [Grunt](http://gruntjs.com/) and [Bower](http://bower.io/). The following tasks are available: + + * `default` compiles the CSS and JS into `/dist` and builds the doc. + * `dist` compiles the CSS and JS into `/dist` only. + * `watch` watches source files and builds them automatically whenever you save. + * `test` runs [JSHint](http://www.jshint.com/) and [QUnit](http://qunitjs.com/) tests headlessly in [PhantomJS](http://phantomjs.org/). + +To define which plugins are build into the distribution just edit `/_config.json` to fit your needs. + +## Contributing + +Please read [CONTRIBUTING.md](CONTRIBUTING.md). + +## Roadmap + +Please make sure to check out our [Roadmap Discussion](https://github.com/OwlCarousel2/OwlCarousel2/issues/1756). + + +## License + +The code and the documentation are released under the [MIT License](LICENSE). diff --git a/resources/js/OwlCarousel2-2.3.4/dist/assets/ajax-loader.gif b/resources/js/OwlCarousel2-2.3.4/dist/assets/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..d3962f969930b0a5cb13fa079f273167082abf68 GIT binary patch literal 3208 zcmc(idr(tX9>*`aH#d)ab@kq01A!Wph)@ebf$~%#K!AWe1Ox$*7!^bXc?bl7@CXUW zGlXYANgy#q6cHbw)$)*nC=6B+wW|xX6~%WMySCd|7u?yIomu|anVspLKhK;wXFlKG z_xqhWTyIZ%hZrWn1m*$YGo|>APn3!m9Z|~{pdHwqJ{QUgP%#2E< zs;#XB{@=>=iK6;!*Y*$Hl1UMrZjvv1yYhs^1bsaFqw2-#}7t+&*K$wzaal zc}SILBCP7W%{Cyca55cabMzW53Embazk6}kyKY^Xpak7>>vytKut)9p=N z#&zsV7gJc3Udctrlfs?7ax8Q4!J^AGlifw@TjK&++1OPA#R?{iM9z?gPGZUr^>h+2N3;46vTw6huczv}pXz08=cw>qDfNw$Oz+Go19x-k^21vVi$xlDAc0uY;bRyaRwCcOlo9NPWrdB6jf0wHNsY1rtD0+?pT|y^-_z9)nn9f zm3GauBd)}{U(S{mi6oj^Ux!~%;0*)zH`0s0k(E${CvR>o!ipxHAD;$hfQF&ICqFy` zI<7Nb+P|9(ckU>e!)~g{_Vbcck&*y?(~DQtCbGU|E0=V@qWjzEs=3kq1|A_RnrfI6 z%|VhFd9d4xhpo%;>FbG`%`R29?j^rBmDaD3g0x7X9d2xyIH|>+vq1paiikK3vH5zM(mk5if-X z(noP}urxYrczrn_p4>Gvlfi2$OTLJ`Y<#{sE?Ubfn|OWrH|?p%z3{SKxHbKtK@1l`MBOIrBGRk}R*Pk)KwzjAbWU!);wJFpXFv zk$v##{JhsQ_Dlr~#$b#YCJuQdO@(_|2+~4V~^_RfQjjqK?Lu7Y%!QkaB@i z$|AtMD4e6RVI`X*y;mz!^Pzl?O|)*b1qcrj85{>v9@RX3TKTPevFTHvIKNlUQ{hui z#ShNmqB?PylOuSj?uH3Yt>m5x7%VaTfay zd*dsR760|i@Ut4~``Emi_-BF2W1<4gb~+Wij@pEO@TTSK>7Q;UK--q_cOa5dQEH{c zRzZE;mz4JlrJa?*XMDDK7mJW!m2}kjpo5vOtO|!~YDrG33ndPKZjtL8 zKoP6dh=?HI@i>RBF1QKPGC5>Y4?3E%t?{9GY@0a#jYpCv4kmCCb=6|ArV9svX$jPo5;+FW*4D~m$Z zg2Y8~2zDcPwjQMKK|w-6>5u5k+3%hYrW=jH>xUHqQw__*^wACE;pg}Bj#;f)vI^h+pEM9Vl1T-w zRtwn&IazcDglIH{sgXF`fx=x30vMacS8EWWd%qzBf&)>jU5FYjPC^hZyx@UhFgMiv zE@E&W#;A{q;k)BAIC0p41K#}sd*S|+_YA23-ea%6=4r&L)Kbc2Y{oV4Nd|(($|^agAFFX^LCJu?zIEcTN60Mdn9}=cnj~zx6dEo zg6|n`Xg^1N=yUr@*$d<~+mY$xr`?wf!n6O$1Z4DEk^ZM5SivT5T1C`#$zvzF@q9&0 zZ|wnQ2u4IQIo|O`hxoj;l0Cdi878u)6lBK8s_p9!E2`;r^;K#~UTB4*)QSkhM;!ff z8B|h72PajO4P5Rf6&ZTOcEz9VAlU&F@EWkFLUc!GJ_y9 z&#s)>sXztCy;q2a_016j>I&ZnUgvfwxu_k5F!C8MjIP1*Up9BjEbUZ+b6Q3=0Tx!p zKJ2HFQd3DuR(8xVTR7j_DZ0=o1tI#c^`K<>D-=?PP!gpXYZNW&sy)SwdUPxX6*#Dr4cJLKQjOTtR}_= zHnbM~`(~u4JyVXaSI`>1U_*ysTcUSxmQ4u|=8X~O?dwm?_} z=;QD{#+OMr+sl?1>}3L0)eEkz1=Ap_(E$8#!5%QOpRa$A8d($mC$1W;|NFH(9QLP3 zFhLXkAEO*B&@g=>2?tY_L&#zgXA!WoNI9gU5(Lc_JNTi{n3erGNR~4bJs$h5ysfbkkTi1Yy4e`VI2mh_>^1it{< z%mz4;Pbkjo9Es=$`_o}HpMSRn^{;q;>3aRUEh_)2D^D{<{`a!}uVw!G6^%Q;yZ?}u zHu#73IDZ<~Ni}$Vsl%0A;2lG!!z>8L*~z#POx} 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 literal 0 HcmV?d00001 diff --git a/resources/js/OwlCarousel2-2.3.4/dist/owl.carousel.js b/resources/js/OwlCarousel2-2.3.4/dist/owl.carousel.js new file mode 100644 index 0000000..9feb680 --- /dev/null +++ b/resources/js/OwlCarousel2-2.3.4/dist/owl.carousel.js @@ -0,0 +1,3452 @@ +import $ from 'jquery'; + +window.jQuery = $; + +/** + * Owl Carousel v2.3.4 + * Copyright 2013-2018 David Deutsch + * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE + */ +/** + * Owl carousel + * @version 2.3.4 + * @author Bartosz Wojciechowski + * @author David Deutsch + * @license The MIT License (MIT) + * @todo Lazy Load Icon + * @todo prevent animationend bubling + * @todo itemsScaleUp + * @todo Test Zepto + * @todo stagePadding calculate wrong active classes + */ +;(function($, window, document, undefined) { + + /** + * Creates a carousel. + * @class The Owl Carousel. + * @public + * @param {HTMLElement|jQuery} element - The element to create the carousel for. + * @param {Object} [options] - The options + */ + function Owl(element, options) { + + /** + * Current settings for the carousel. + * @public + */ + this.settings = null; + + /** + * Current options set by the caller including defaults. + * @public + */ + this.options = $.extend({}, Owl.Defaults, options); + + /** + * Plugin element. + * @public + */ + this.$element = $(element); + + /** + * Proxied event handlers. + * @protected + */ + this._handlers = {}; + + /** + * References to the running plugins of this carousel. + * @protected + */ + this._plugins = {}; + + /** + * Currently suppressed events to prevent them from being retriggered. + * @protected + */ + this._supress = {}; + + /** + * Absolute current position. + * @protected + */ + this._current = null; + + /** + * Animation speed in milliseconds. + * @protected + */ + this._speed = null; + + /** + * Coordinates of all items in pixel. + * @todo The name of this member is missleading. + * @protected + */ + this._coordinates = []; + + /** + * Current breakpoint. + * @todo Real media queries would be nice. + * @protected + */ + this._breakpoint = null; + + /** + * Current width of the plugin element. + */ + this._width = null; + + /** + * All real items. + * @protected + */ + this._items = []; + + /** + * All cloned items. + * @protected + */ + this._clones = []; + + /** + * Merge values of all items. + * @todo Maybe this could be part of a plugin. + * @protected + */ + this._mergers = []; + + /** + * Widths of all items. + */ + this._widths = []; + + /** + * Invalidated parts within the update process. + * @protected + */ + this._invalidated = {}; + + /** + * Ordered list of workers for the update process. + * @protected + */ + this._pipe = []; + + /** + * Current state information for the drag operation. + * @todo #261 + * @protected + */ + this._drag = { + time: null, + target: null, + pointer: null, + stage: { + start: null, + current: null + }, + direction: null + }; + + /** + * Current state information and their tags. + * @type {Object} + * @protected + */ + this._states = { + current: {}, + tags: { + 'initializing': [ 'busy' ], + 'animating': [ 'busy' ], + 'dragging': [ 'interacting' ] + } + }; + + $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) { + this._handlers[handler] = $.proxy(this[handler], this); + }, this)); + + $.each(Owl.Plugins, $.proxy(function(key, plugin) { + this._plugins[key.charAt(0).toLowerCase() + key.slice(1)] + = new plugin(this); + }, this)); + + $.each(Owl.Workers, $.proxy(function(priority, worker) { + this._pipe.push({ + 'filter': worker.filter, + 'run': $.proxy(worker.run, this) + }); + }, this)); + + this.setup(); + this.initialize(); + } + + /** + * Default options for the carousel. + * @public + */ + Owl.Defaults = { + items: 3, + loop: false, + center: false, + rewind: false, + checkVisibility: true, + + mouseDrag: true, + touchDrag: true, + pullDrag: true, + freeDrag: false, + + margin: 0, + stagePadding: 0, + + merge: false, + mergeFit: true, + autoWidth: false, + + startPosition: 0, + rtl: false, + + smartSpeed: 250, + fluidSpeed: false, + dragEndSpeed: false, + + responsive: {}, + responsiveRefreshRate: 200, + responsiveBaseElement: window, + + fallbackEasing: 'swing', + slideTransition: '', + + info: false, + + nestedItemSelector: false, + itemElement: 'div', + stageElement: 'div', + + refreshClass: 'owl-refresh', + loadedClass: 'owl-loaded', + loadingClass: 'owl-loading', + rtlClass: 'owl-rtl', + responsiveClass: 'owl-responsive', + dragClass: 'owl-drag', + itemClass: 'owl-item', + stageClass: 'owl-stage', + stageOuterClass: 'owl-stage-outer', + grabClass: 'owl-grab' + }; + + /** + * Enumeration for width. + * @public + * @readonly + * @enum {String} + */ + Owl.Width = { + Default: 'default', + Inner: 'inner', + Outer: 'outer' + }; + + /** + * Enumeration for types. + * @public + * @readonly + * @enum {String} + */ + Owl.Type = { + Event: 'event', + State: 'state' + }; + + /** + * Contains all registered plugins. + * @public + */ + Owl.Plugins = {}; + + /** + * List of workers involved in the update process. + */ + Owl.Workers = [ { + filter: [ 'width', 'settings' ], + run: function() { + this._width = this.$element.width(); + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function(cache) { + cache.current = this._items && this._items[this.relative(this._current)]; + } + }, { + filter: [ 'items', 'settings' ], + run: function() { + this.$stage.children('.cloned').remove(); + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function(cache) { + var margin = this.settings.margin || '', + grid = !this.settings.autoWidth, + rtl = this.settings.rtl, + css = { + 'width': 'auto', + 'margin-left': rtl ? margin : '', + 'margin-right': rtl ? '' : margin + }; + + !grid && this.$stage.children().css(css); + + cache.css = css; + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function(cache) { + var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin, + merge = null, + iterator = this._items.length, + grid = !this.settings.autoWidth, + widths = []; + + cache.items = { + merge: false, + width: width + }; + + while (iterator--) { + merge = this._mergers[iterator]; + merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge; + + cache.items.merge = merge > 1 || cache.items.merge; + + widths[iterator] = !grid ? this._items[iterator].width() : width * merge; + } + + this._widths = widths; + } + }, { + filter: [ 'items', 'settings' ], + run: function() { + var clones = [], + items = this._items, + settings = this.settings, + // TODO: Should be computed from number of min width items in stage + view = Math.max(settings.items * 2, 4), + size = Math.ceil(items.length / 2) * 2, + repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0, + append = '', + prepend = ''; + + repeat /= 2; + + while (repeat > 0) { + // Switch to only using appended clones + clones.push(this.normalize(clones.length / 2, true)); + append = append + items[clones[clones.length - 1]][0].outerHTML; + clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true)); + prepend = items[clones[clones.length - 1]][0].outerHTML + prepend; + repeat -= 1; + } + + this._clones = clones; + + $(append).addClass('cloned').appendTo(this.$stage); + $(prepend).addClass('cloned').prependTo(this.$stage); + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function() { + var rtl = this.settings.rtl ? 1 : -1, + size = this._clones.length + this._items.length, + iterator = -1, + previous = 0, + current = 0, + coordinates = []; + + while (++iterator < size) { + previous = coordinates[iterator - 1] || 0; + current = this._widths[this.relative(iterator)] + this.settings.margin; + coordinates.push(previous + current * rtl); + } + + this._coordinates = coordinates; + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function() { + var padding = this.settings.stagePadding, + coordinates = this._coordinates, + css = { + 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2, + 'padding-left': padding || '', + 'padding-right': padding || '' + }; + + this.$stage.css(css); + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function(cache) { + var iterator = this._coordinates.length, + grid = !this.settings.autoWidth, + items = this.$stage.children(); + + if (grid && cache.items.merge) { + while (iterator--) { + cache.css.width = this._widths[this.relative(iterator)]; + items.eq(iterator).css(cache.css); + } + } else if (grid) { + cache.css.width = cache.items.width; + items.css(cache.css); + } + } + }, { + filter: [ 'items' ], + run: function() { + this._coordinates.length < 1 && this.$stage.removeAttr('style'); + } + }, { + filter: [ 'width', 'items', 'settings' ], + run: function(cache) { + cache.current = cache.current ? this.$stage.children().index(cache.current) : 0; + cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current)); + this.reset(cache.current); + } + }, { + filter: [ 'position' ], + run: function() { + this.animate(this.coordinates(this._current)); + } + }, { + filter: [ 'width', 'position', 'items', 'settings' ], + run: function() { + var rtl = this.settings.rtl ? 1 : -1, + padding = this.settings.stagePadding * 2, + begin = this.coordinates(this.current()) + padding, + end = begin + this.width() * rtl, + inner, outer, matches = [], i, n; + + for (i = 0, n = this._coordinates.length; i < n; i++) { + inner = this._coordinates[i - 1] || 0; + outer = Math.abs(this._coordinates[i]) + padding * rtl; + + if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end))) + || (this.op(outer, '<', begin) && this.op(outer, '>', end))) { + matches.push(i); + } + } + + this.$stage.children('.active').removeClass('active'); + this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active'); + + this.$stage.children('.center').removeClass('center'); + if (this.settings.center) { + this.$stage.children().eq(this.current()).addClass('center'); + } + } + } ]; + + /** + * Create the stage DOM element + */ + Owl.prototype.initializeStage = function() { + this.$stage = this.$element.find('.' + this.settings.stageClass); + + // if the stage is already in the DOM, grab it and skip stage initialization + if (this.$stage.length) { + return; + } + + this.$element.addClass(this.options.loadingClass); + + // create stage + this.$stage = $('<' + this.settings.stageElement + '>', { + "class": this.settings.stageClass + }).wrap( $( '
', { + "class": this.settings.stageOuterClass + })); + + // append stage + this.$element.append(this.$stage.parent()); + }; + + /** + * Create item DOM elements + */ + Owl.prototype.initializeItems = function() { + var $items = this.$element.find('.owl-item'); + + // if the items are already in the DOM, grab them and skip item initialization + if ($items.length) { + this._items = $items.get().map(function(item) { + return $(item); + }); + + this._mergers = this._items.map(function() { + return 1; + }); + + this.refresh(); + + return; + } + + // append content + this.replace(this.$element.children().not(this.$stage.parent())); + + // check visibility + if (this.isVisible()) { + // update view + this.refresh(); + } else { + // invalidate width + this.invalidate('width'); + } + + this.$element + .removeClass(this.options.loadingClass) + .addClass(this.options.loadedClass); + }; + + /** + * Initializes the carousel. + * @protected + */ + Owl.prototype.initialize = function() { + this.enter('initializing'); + this.trigger('initialize'); + + this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl); + + if (this.settings.autoWidth && !this.is('pre-loading')) { + var imgs, nestedSelector, width; + imgs = this.$element.find('img'); + nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined; + width = this.$element.children(nestedSelector).width(); + + if (imgs.length && width <= 0) { + this.preloadAutoWidthImages(imgs); + } + } + + this.initializeStage(); + this.initializeItems(); + + // register event handlers + this.registerEventHandlers(); + + this.leave('initializing'); + this.trigger('initialized'); + }; + + /** + * @returns {Boolean} visibility of $element + * if you know the carousel will always be visible you can set `checkVisibility` to `false` to + * prevent the expensive browser layout forced reflow the $element.is(':visible') does + */ + Owl.prototype.isVisible = function() { + return this.settings.checkVisibility + ? this.$element.is(':visible') + : true; + }; + + /** + * Setups the current settings. + * @todo Remove responsive classes. Why should adaptive designs be brought into IE8? + * @todo Support for media queries by using `matchMedia` would be nice. + * @public + */ + Owl.prototype.setup = function() { + var viewport = this.viewport(), + overwrites = this.options.responsive, + match = -1, + settings = null; + + if (!overwrites) { + settings = $.extend({}, this.options); + } else { + $.each(overwrites, function(breakpoint) { + if (breakpoint <= viewport && breakpoint > match) { + match = Number(breakpoint); + } + }); + + settings = $.extend({}, this.options, overwrites[match]); + if (typeof settings.stagePadding === 'function') { + settings.stagePadding = settings.stagePadding(); + } + delete settings.responsive; + + // responsive class + if (settings.responsiveClass) { + this.$element.attr('class', + this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match) + ); + } + } + + this.trigger('change', { property: { name: 'settings', value: settings } }); + this._breakpoint = match; + this.settings = settings; + this.invalidate('settings'); + this.trigger('changed', { property: { name: 'settings', value: this.settings } }); + }; + + /** + * Updates option logic if necessery. + * @protected + */ + Owl.prototype.optionsLogic = function() { + if (this.settings.autoWidth) { + this.settings.stagePadding = false; + this.settings.merge = false; + } + }; + + /** + * Prepares an item before add. + * @todo Rename event parameter `content` to `item`. + * @protected + * @returns {jQuery|HTMLElement} - The item container. + */ + Owl.prototype.prepare = function(item) { + var event = this.trigger('prepare', { content: item }); + + if (!event.data) { + event.data = $('<' + this.settings.itemElement + '/>') + .addClass(this.options.itemClass).append(item) + } + + this.trigger('prepared', { content: event.data }); + + return event.data; + }; + + /** + * Updates the view. + * @public + */ + Owl.prototype.update = function() { + var i = 0, + n = this._pipe.length, + filter = $.proxy(function(p) { return this[p] }, this._invalidated), + cache = {}; + + while (i < n) { + if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) { + this._pipe[i].run(cache); + } + i++; + } + + this._invalidated = {}; + + !this.is('valid') && this.enter('valid'); + }; + + /** + * Gets the width of the view. + * @public + * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return. + * @returns {Number} - The width of the view in pixel. + */ + Owl.prototype.width = function(dimension) { + dimension = dimension || Owl.Width.Default; + switch (dimension) { + case Owl.Width.Inner: + case Owl.Width.Outer: + return this._width; + default: + return this._width - this.settings.stagePadding * 2 + this.settings.margin; + } + }; + + /** + * Refreshes the carousel primarily for adaptive purposes. + * @public + */ + Owl.prototype.refresh = function() { + this.enter('refreshing'); + this.trigger('refresh'); + + this.setup(); + + this.optionsLogic(); + + this.$element.addClass(this.options.refreshClass); + + this.update(); + + this.$element.removeClass(this.options.refreshClass); + + this.leave('refreshing'); + this.trigger('refreshed'); + }; + + /** + * Checks window `resize` event. + * @protected + */ + Owl.prototype.onThrottledResize = function() { + window.clearTimeout(this.resizeTimer); + this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate); + }; + + /** + * Checks window `resize` event. + * @protected + */ + Owl.prototype.onResize = function() { + if (!this._items.length) { + return false; + } + + if (this._width === this.$element.width()) { + return false; + } + + if (!this.isVisible()) { + return false; + } + + this.enter('resizing'); + + if (this.trigger('resize').isDefaultPrevented()) { + this.leave('resizing'); + return false; + } + + this.invalidate('width'); + + this.refresh(); + + this.leave('resizing'); + this.trigger('resized'); + }; + + /** + * Registers event handlers. + * @todo Check `msPointerEnabled` + * @todo #261 + * @protected + */ + Owl.prototype.registerEventHandlers = function() { + if ($.support.transition) { + this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this)); + } + + if (this.settings.responsive !== false) { + this.on(window, 'resize', this._handlers.onThrottledResize); + } + + if (this.settings.mouseDrag) { + this.$element.addClass(this.options.dragClass); + this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this)); + this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false }); + } + + if (this.settings.touchDrag){ + this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this)); + this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this)); + } + }; + + /** + * Handles `touchstart` and `mousedown` events. + * @todo Horizontal swipe threshold as option + * @todo #261 + * @protected + * @param {Event} event - The event arguments. + */ + Owl.prototype.onDragStart = function(event) { + var stage = null; + + if (event.which === 3) { + return; + } + + if ($.support.transform) { + stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(','); + stage = { + x: stage[stage.length === 16 ? 12 : 4], + y: stage[stage.length === 16 ? 13 : 5] + }; + } else { + stage = this.$stage.position(); + stage = { + x: this.settings.rtl ? + stage.left + this.$stage.width() - this.width() + this.settings.margin : + stage.left, + y: stage.top + }; + } + + if (this.is('animating')) { + $.support.transform ? this.animate(stage.x) : this.$stage.stop() + this.invalidate('position'); + } + + this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown'); + + this.speed(0); + + this._drag.time = new Date().getTime(); + this._drag.target = $(event.target); + this._drag.stage.start = stage; + this._drag.stage.current = stage; + this._drag.pointer = this.pointer(event); + + $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this)); + + $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) { + var delta = this.difference(this._drag.pointer, this.pointer(event)); + + $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this)); + + if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) { + return; + } + + event.preventDefault(); + + this.enter('dragging'); + this.trigger('drag'); + }, this)); + }; + + /** + * Handles the `touchmove` and `mousemove` events. + * @todo #261 + * @protected + * @param {Event} event - The event arguments. + */ + Owl.prototype.onDragMove = function(event) { + var minimum = null, + maximum = null, + pull = null, + delta = this.difference(this._drag.pointer, this.pointer(event)), + stage = this.difference(this._drag.stage.start, delta); + + if (!this.is('dragging')) { + return; + } + + event.preventDefault(); + + if (this.settings.loop) { + minimum = this.coordinates(this.minimum()); + maximum = this.coordinates(this.maximum() + 1) - minimum; + stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum; + } else { + minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum()); + maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum()); + pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0; + stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull); + } + + this._drag.stage.current = stage; + + this.animate(stage.x); + }; + + /** + * Handles the `touchend` and `mouseup` events. + * @todo #261 + * @todo Threshold for click event + * @protected + * @param {Event} event - The event arguments. + */ + Owl.prototype.onDragEnd = function(event) { + var delta = this.difference(this._drag.pointer, this.pointer(event)), + stage = this._drag.stage.current, + direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right'; + + $(document).off('.owl.core'); + + this.$element.removeClass(this.options.grabClass); + + if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) { + this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed); + this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction)); + this.invalidate('position'); + this.update(); + + this._drag.direction = direction; + + if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) { + this._drag.target.one('click.owl.core', function() { return false; }); + } + } + + if (!this.is('dragging')) { + return; + } + + this.leave('dragging'); + this.trigger('dragged'); + }; + + /** + * Gets absolute position of the closest item for a coordinate. + * @todo Setting `freeDrag` makes `closest` not reusable. See #165. + * @protected + * @param {Number} coordinate - The coordinate in pixel. + * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`. + * @return {Number} - The absolute position of the closest item. + */ + Owl.prototype.closest = function(coordinate, direction) { + var position = -1, + pull = 30, + width = this.width(), + coordinates = this.coordinates(); + + if (!this.settings.freeDrag) { + // check closest item + $.each(coordinates, $.proxy(function(index, value) { + // on a left pull, check on current index + if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) { + position = index; + // on a right pull, check on previous index + // to do so, subtract width from value and set position = index + 1 + } else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) { + position = index + 1; + } else if (this.op(coordinate, '<', value) + && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) { + position = direction === 'left' ? index + 1 : index; + } + return position === -1; + }, this)); + } + + if (!this.settings.loop) { + // non loop boundries + if (this.op(coordinate, '>', coordinates[this.minimum()])) { + position = coordinate = this.minimum(); + } else if (this.op(coordinate, '<', coordinates[this.maximum()])) { + position = coordinate = this.maximum(); + } + } + + return position; + }; + + /** + * Animates the stage. + * @todo #270 + * @public + * @param {Number} coordinate - The coordinate in pixels. + */ + Owl.prototype.animate = function(coordinate) { + var animate = this.speed() > 0; + + this.is('animating') && this.onTransitionEnd(); + + if (animate) { + this.enter('animating'); + this.trigger('translate'); + } + + if ($.support.transform3d && $.support.transition) { + this.$stage.css({ + transform: 'translate3d(' + coordinate + 'px,0px,0px)', + transition: (this.speed() / 1000) + 's' + ( + this.settings.slideTransition ? ' ' + this.settings.slideTransition : '' + ) + }); + } else if (animate) { + this.$stage.animate({ + left: coordinate + 'px' + }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this)); + } else { + this.$stage.css({ + left: coordinate + 'px' + }); + } + }; + + /** + * Checks whether the carousel is in a specific state or not. + * @param {String} state - The state to check. + * @returns {Boolean} - The flag which indicates if the carousel is busy. + */ + Owl.prototype.is = function(state) { + return this._states.current[state] && this._states.current[state] > 0; + }; + + /** + * Sets the absolute position of the current item. + * @public + * @param {Number} [position] - The new absolute position or nothing to leave it unchanged. + * @returns {Number} - The absolute position of the current item. + */ + Owl.prototype.current = function(position) { + if (position === undefined) { + return this._current; + } + + if (this._items.length === 0) { + return undefined; + } + + position = this.normalize(position); + + if (this._current !== position) { + var event = this.trigger('change', { property: { name: 'position', value: position } }); + + if (event.data !== undefined) { + position = this.normalize(event.data); + } + + this._current = position; + + this.invalidate('position'); + + this.trigger('changed', { property: { name: 'position', value: this._current } }); + } + + return this._current; + }; + + /** + * Invalidates the given part of the update routine. + * @param {String} [part] - The part to invalidate. + * @returns {Array.} - The invalidated parts. + */ + Owl.prototype.invalidate = function(part) { + if ($.type(part) === 'string') { + this._invalidated[part] = true; + this.is('valid') && this.leave('valid'); + } + return $.map(this._invalidated, function(v, i) { return i }); + }; + + /** + * Resets the absolute position of the current item. + * @public + * @param {Number} position - The absolute position of the new item. + */ + Owl.prototype.reset = function(position) { + position = this.normalize(position); + + if (position === undefined) { + return; + } + + this._speed = 0; + this._current = position; + + this.suppress([ 'translate', 'translated' ]); + + this.animate(this.coordinates(position)); + + this.release([ 'translate', 'translated' ]); + }; + + /** + * Normalizes an absolute or a relative position of an item. + * @public + * @param {Number} position - The absolute or relative position to normalize. + * @param {Boolean} [relative=false] - Whether the given position is relative or not. + * @returns {Number} - The normalized position. + */ + Owl.prototype.normalize = function(position, relative) { + var n = this._items.length, + m = relative ? 0 : this._clones.length; + + if (!this.isNumeric(position) || n < 1) { + position = undefined; + } else if (position < 0 || position >= n + m) { + position = ((position - m / 2) % n + n) % n + m / 2; + } + + return position; + }; + + /** + * Converts an absolute position of an item into a relative one. + * @public + * @param {Number} position - The absolute position to convert. + * @returns {Number} - The converted position. + */ + Owl.prototype.relative = function(position) { + position -= this._clones.length / 2; + return this.normalize(position, true); + }; + + /** + * Gets the maximum position for the current item. + * @public + * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. + * @returns {Number} + */ + Owl.prototype.maximum = function(relative) { + var settings = this.settings, + maximum = this._coordinates.length, + iterator, + reciprocalItemsWidth, + elementWidth; + + if (settings.loop) { + maximum = this._clones.length / 2 + this._items.length - 1; + } else if (settings.autoWidth || settings.merge) { + iterator = this._items.length; + if (iterator) { + reciprocalItemsWidth = this._items[--iterator].width(); + elementWidth = this.$element.width(); + while (iterator--) { + reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin; + if (reciprocalItemsWidth > elementWidth) { + break; + } + } + } + maximum = iterator + 1; + } else if (settings.center) { + maximum = this._items.length - 1; + } else { + maximum = this._items.length - settings.items; + } + + if (relative) { + maximum -= this._clones.length / 2; + } + + return Math.max(maximum, 0); + }; + + /** + * Gets the minimum position for the current item. + * @public + * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position. + * @returns {Number} + */ + Owl.prototype.minimum = function(relative) { + return relative ? 0 : this._clones.length / 2; + }; + + /** + * Gets an item at the specified relative position. + * @public + * @param {Number} [position] - The relative position of the item. + * @return {jQuery|Array.} - The item at the given position or all items if no position was given. + */ + Owl.prototype.items = function(position) { + if (position === undefined) { + return this._items.slice(); + } + + position = this.normalize(position, true); + return this._items[position]; + }; + + /** + * Gets an item at the specified relative position. + * @public + * @param {Number} [position] - The relative position of the item. + * @return {jQuery|Array.} - The item at the given position or all items if no position was given. + */ + Owl.prototype.mergers = function(position) { + if (position === undefined) { + return this._mergers.slice(); + } + + position = this.normalize(position, true); + return this._mergers[position]; + }; + + /** + * Gets the absolute positions of clones for an item. + * @public + * @param {Number} [position] - The relative position of the item. + * @returns {Array.} - The absolute positions of clones for the item or all if no position was given. + */ + Owl.prototype.clones = function(position) { + var odd = this._clones.length / 2, + even = odd + this._items.length, + map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 }; + + if (position === undefined) { + return $.map(this._clones, function(v, i) { return map(i) }); + } + + return $.map(this._clones, function(v, i) { return v === position ? map(i) : null }); + }; + + /** + * Sets the current animation speed. + * @public + * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged. + * @returns {Number} - The current animation speed in milliseconds. + */ + Owl.prototype.speed = function(speed) { + if (speed !== undefined) { + this._speed = speed; + } + + return this._speed; + }; + + /** + * Gets the coordinate of an item. + * @todo The name of this method is missleanding. + * @public + * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`. + * @returns {Number|Array.} - The coordinate of the item in pixel or all coordinates. + */ + Owl.prototype.coordinates = function(position) { + var multiplier = 1, + newPosition = position - 1, + coordinate; + + if (position === undefined) { + return $.map(this._coordinates, $.proxy(function(coordinate, index) { + return this.coordinates(index); + }, this)); + } + + if (this.settings.center) { + if (this.settings.rtl) { + multiplier = -1; + newPosition = position + 1; + } + + coordinate = this._coordinates[position]; + coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier; + } else { + coordinate = this._coordinates[newPosition] || 0; + } + + coordinate = Math.ceil(coordinate); + + return coordinate; + }; + + /** + * Calculates the speed for a translation. + * @protected + * @param {Number} from - The absolute position of the start item. + * @param {Number} to - The absolute position of the target item. + * @param {Number} [factor=undefined] - The time factor in milliseconds. + * @returns {Number} - The time in milliseconds for the translation. + */ + Owl.prototype.duration = function(from, to, factor) { + if (factor === 0) { + return 0; + } + + return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed)); + }; + + /** + * Slides to the specified item. + * @public + * @param {Number} position - The position of the item. + * @param {Number} [speed] - The time in milliseconds for the transition. + */ + Owl.prototype.to = function(position, speed) { + var current = this.current(), + revert = null, + distance = position - this.relative(current), + direction = (distance > 0) - (distance < 0), + items = this._items.length, + minimum = this.minimum(), + maximum = this.maximum(); + + if (this.settings.loop) { + if (!this.settings.rewind && Math.abs(distance) > items / 2) { + distance += direction * -1 * items; + } + + position = current + distance; + revert = ((position - minimum) % items + items) % items + minimum; + + if (revert !== position && revert - distance <= maximum && revert - distance > 0) { + current = revert - distance; + position = revert; + this.reset(current); + } + } else if (this.settings.rewind) { + maximum += 1; + position = (position % maximum + maximum) % maximum; + } else { + position = Math.max(minimum, Math.min(maximum, position)); + } + + this.speed(this.duration(current, position, speed)); + this.current(position); + + if (this.isVisible()) { + this.update(); + } + }; + + /** + * Slides to the next item. + * @public + * @param {Number} [speed] - The time in milliseconds for the transition. + */ + Owl.prototype.next = function(speed) { + speed = speed || false; + this.to(this.relative(this.current()) + 1, speed); + }; + + /** + * Slides to the previous item. + * @public + * @param {Number} [speed] - The time in milliseconds for the transition. + */ + Owl.prototype.prev = function(speed) { + speed = speed || false; + this.to(this.relative(this.current()) - 1, speed); + }; + + /** + * Handles the end of an animation. + * @protected + * @param {Event} event - The event arguments. + */ + Owl.prototype.onTransitionEnd = function(event) { + + // if css2 animation then event object is undefined + if (event !== undefined) { + event.stopPropagation(); + + // Catch only owl-stage transitionEnd event + if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) { + return false; + } + } + + this.leave('animating'); + this.trigger('translated'); + }; + + /** + * Gets viewport width. + * @protected + * @return {Number} - The width in pixel. + */ + Owl.prototype.viewport = function() { + var width; + if (this.options.responsiveBaseElement !== window) { + width = $(this.options.responsiveBaseElement).width(); + } else if (window.innerWidth) { + width = window.innerWidth; + } else if (document.documentElement && document.documentElement.clientWidth) { + width = document.documentElement.clientWidth; + } else { + console.warn('Can not detect viewport width.'); + } + return width; + }; + + /** + * Replaces the current content. + * @public + * @param {HTMLElement|jQuery|String} content - The new content. + */ + Owl.prototype.replace = function(content) { + this.$stage.empty(); + this._items = []; + + if (content) { + content = (content instanceof jQuery) ? content : $(content); + } + + if (this.settings.nestedItemSelector) { + content = content.find('.' + this.settings.nestedItemSelector); + } + + content.filter(function() { + return this.nodeType === 1; + }).each($.proxy(function(index, item) { + item = this.prepare(item); + this.$stage.append(item); + this._items.push(item); + this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); + }, this)); + + this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0); + + this.invalidate('items'); + }; + + /** + * Adds an item. + * @todo Use `item` instead of `content` for the event arguments. + * @public + * @param {HTMLElement|jQuery|String} content - The item content to add. + * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end. + */ + Owl.prototype.add = function(content, position) { + var current = this.relative(this._current); + + position = position === undefined ? this._items.length : this.normalize(position, true); + content = content instanceof jQuery ? content : $(content); + + this.trigger('add', { content: content, position: position }); + + content = this.prepare(content); + + if (this._items.length === 0 || position === this._items.length) { + this._items.length === 0 && this.$stage.append(content); + this._items.length !== 0 && this._items[position - 1].after(content); + this._items.push(content); + this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); + } else { + this._items[position].before(content); + this._items.splice(position, 0, content); + this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1); + } + + this._items[current] && this.reset(this._items[current].index()); + + this.invalidate('items'); + + this.trigger('added', { content: content, position: position }); + }; + + /** + * Removes an item by its position. + * @todo Use `item` instead of `content` for the event arguments. + * @public + * @param {Number} position - The relative position of the item to remove. + */ + Owl.prototype.remove = function(position) { + position = this.normalize(position, true); + + if (position === undefined) { + return; + } + + this.trigger('remove', { content: this._items[position], position: position }); + + this._items[position].remove(); + this._items.splice(position, 1); + this._mergers.splice(position, 1); + + this.invalidate('items'); + + this.trigger('removed', { content: null, position: position }); + }; + + /** + * Preloads images with auto width. + * @todo Replace by a more generic approach + * @protected + */ + Owl.prototype.preloadAutoWidthImages = function(images) { + images.each($.proxy(function(i, element) { + this.enter('pre-loading'); + element = $(element); + $(new Image()).one('load', $.proxy(function(e) { + element.attr('src', e.target.src); + element.css('opacity', 1); + this.leave('pre-loading'); + !this.is('pre-loading') && !this.is('initializing') && this.refresh(); + }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina')); + }, this)); + }; + + /** + * Destroys the carousel. + * @public + */ + Owl.prototype.destroy = function() { + + this.$element.off('.owl.core'); + this.$stage.off('.owl.core'); + $(document).off('.owl.core'); + + if (this.settings.responsive !== false) { + window.clearTimeout(this.resizeTimer); + this.off(window, 'resize', this._handlers.onThrottledResize); + } + + for (var i in this._plugins) { + this._plugins[i].destroy(); + } + + this.$stage.children('.cloned').remove(); + + this.$stage.unwrap(); + this.$stage.children().contents().unwrap(); + this.$stage.children().unwrap(); + this.$stage.remove(); + this.$element + .removeClass(this.options.refreshClass) + .removeClass(this.options.loadingClass) + .removeClass(this.options.loadedClass) + .removeClass(this.options.rtlClass) + .removeClass(this.options.dragClass) + .removeClass(this.options.grabClass) + .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), '')) + .removeData('owl.carousel'); + }; + + /** + * Operators to calculate right-to-left and left-to-right. + * @protected + * @param {Number} [a] - The left side operand. + * @param {String} [o] - The operator. + * @param {Number} [b] - The right side operand. + */ + Owl.prototype.op = function(a, o, b) { + var rtl = this.settings.rtl; + switch (o) { + case '<': + return rtl ? a > b : a < b; + case '>': + return rtl ? a < b : a > b; + case '>=': + return rtl ? a <= b : a >= b; + case '<=': + return rtl ? a >= b : a <= b; + default: + break; + } + }; + + /** + * Attaches to an internal event. + * @protected + * @param {HTMLElement} element - The event source. + * @param {String} event - The event name. + * @param {Function} listener - The event handler to attach. + * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not. + */ + Owl.prototype.on = function(element, event, listener, capture) { + if (element.addEventListener) { + element.addEventListener(event, listener, capture); + } else if (element.attachEvent) { + element.attachEvent('on' + event, listener); + } + }; + + /** + * Detaches from an internal event. + * @protected + * @param {HTMLElement} element - The event source. + * @param {String} event - The event name. + * @param {Function} listener - The attached event handler to detach. + * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not. + */ + Owl.prototype.off = function(element, event, listener, capture) { + if (element.removeEventListener) { + element.removeEventListener(event, listener, capture); + } else if (element.detachEvent) { + element.detachEvent('on' + event, listener); + } + }; + + /** + * Triggers a public event. + * @todo Remove `status`, `relatedTarget` should be used instead. + * @protected + * @param {String} name - The event name. + * @param {*} [data=null] - The event data. + * @param {String} [namespace=carousel] - The event namespace. + * @param {String} [state] - The state which is associated with the event. + * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not. + * @returns {Event} - The event arguments. + */ + Owl.prototype.trigger = function(name, data, namespace, state, enter) { + var status = { + item: { count: this._items.length, index: this.current() } + }, handler = $.camelCase( + $.grep([ 'on', name, namespace ], function(v) { return v }) + .join('-').toLowerCase() + ), event = $.Event( + [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(), + $.extend({ relatedTarget: this }, status, data) + ); + + if (!this._supress[name]) { + $.each(this._plugins, function(name, plugin) { + if (plugin.onTrigger) { + plugin.onTrigger(event); + } + }); + + this.register({ type: Owl.Type.Event, name: name }); + this.$element.trigger(event); + + if (this.settings && typeof this.settings[handler] === 'function') { + this.settings[handler].call(this, event); + } + } + + return event; + }; + + /** + * Enters a state. + * @param name - The state name. + */ + Owl.prototype.enter = function(name) { + $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { + if (this._states.current[name] === undefined) { + this._states.current[name] = 0; + } + + this._states.current[name]++; + }, this)); + }; + + /** + * Leaves a state. + * @param name - The state name. + */ + Owl.prototype.leave = function(name) { + $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) { + this._states.current[name]--; + }, this)); + }; + + /** + * Registers an event or state. + * @public + * @param {Object} object - The event or state to register. + */ + Owl.prototype.register = function(object) { + if (object.type === Owl.Type.Event) { + if (!$.event.special[object.name]) { + $.event.special[object.name] = {}; + } + + if (!$.event.special[object.name].owl) { + var _default = $.event.special[object.name]._default; + $.event.special[object.name]._default = function(e) { + if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) { + return _default.apply(this, arguments); + } + return e.namespace && e.namespace.indexOf('owl') > -1; + }; + $.event.special[object.name].owl = true; + } + } else if (object.type === Owl.Type.State) { + if (!this._states.tags[object.name]) { + this._states.tags[object.name] = object.tags; + } else { + this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags); + } + + this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) { + return $.inArray(tag, this._states.tags[object.name]) === i; + }, this)); + } + }; + + /** + * Suppresses events. + * @protected + * @param {Array.} events - The events to suppress. + */ + Owl.prototype.suppress = function(events) { + $.each(events, $.proxy(function(index, event) { + this._supress[event] = true; + }, this)); + }; + + /** + * Releases suppressed events. + * @protected + * @param {Array.} events - The events to release. + */ + Owl.prototype.release = function(events) { + $.each(events, $.proxy(function(index, event) { + delete this._supress[event]; + }, this)); + }; + + /** + * Gets unified pointer coordinates from event. + * @todo #261 + * @protected + * @param {Event} - The `mousedown` or `touchstart` event. + * @returns {Object} - Contains `x` and `y` coordinates of current pointer position. + */ + Owl.prototype.pointer = function(event) { + var result = { x: null, y: null }; + + event = event.originalEvent || event || window.event; + + event = event.touches && event.touches.length ? + event.touches[0] : event.changedTouches && event.changedTouches.length ? + event.changedTouches[0] : event; + + if (event.pageX) { + result.x = event.pageX; + result.y = event.pageY; + } else { + result.x = event.clientX; + result.y = event.clientY; + } + + return result; + }; + + /** + * Determines if the input is a Number or something that can be coerced to a Number + * @protected + * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested + * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number + */ + Owl.prototype.isNumeric = function(number) { + return !isNaN(parseFloat(number)); + }; + + /** + * Gets the difference of two vectors. + * @todo #261 + * @protected + * @param {Object} - The first vector. + * @param {Object} - The second vector. + * @returns {Object} - The difference. + */ + Owl.prototype.difference = function(first, second) { + return { + x: first.x - second.x, + y: first.y - second.y + }; + }; + + /** + * The jQuery Plugin for the Owl Carousel + * @todo Navigation plugin `next` and `prev` + * @public + */ + $.fn.owlCarousel = function(option) { + var args = Array.prototype.slice.call(arguments, 1); + + return this.each(function() { + var $this = $(this), + data = $this.data('owl.carousel'); + + if (!data) { + data = new Owl(this, typeof option == 'object' && option); + $this.data('owl.carousel', data); + + $.each([ + 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove' + ], function(i, event) { + data.register({ type: Owl.Type.Event, name: event }); + data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) { + if (e.namespace && e.relatedTarget !== this) { + this.suppress([ event ]); + data[event].apply(this, [].slice.call(arguments, 1)); + this.release([ event ]); + } + }, data)); + }); + } + + if (typeof option == 'string' && option.charAt(0) !== '_') { + data[option].apply(data, args); + } + }); + }; + + /** + * The constructor for the jQuery Plugin + * @public + */ + $.fn.owlCarousel.Constructor = Owl; + +})(window.Zepto || window.jQuery, window, document); + +/** + * AutoRefresh Plugin + * @version 2.3.4 + * @author Artus Kolanowski + * @author David Deutsch + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + + /** + * Creates the auto refresh plugin. + * @class The Auto Refresh Plugin + * @param {Owl} carousel - The Owl Carousel + */ + var AutoRefresh = function(carousel) { + /** + * Reference to the core. + * @protected + * @type {Owl} + */ + this._core = carousel; + + /** + * Refresh interval. + * @protected + * @type {number} + */ + this._interval = null; + + /** + * Whether the element is currently visible or not. + * @protected + * @type {Boolean} + */ + this._visible = null; + + /** + * All event handlers. + * @protected + * @type {Object} + */ + this._handlers = { + 'initialized.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.autoRefresh) { + this.watch(); + } + }, this) + }; + + // set default options + this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options); + + // register event handlers + this._core.$element.on(this._handlers); + }; + + /** + * Default options. + * @public + */ + AutoRefresh.Defaults = { + autoRefresh: true, + autoRefreshInterval: 500 + }; + + /** + * Watches the element. + */ + AutoRefresh.prototype.watch = function() { + if (this._interval) { + return; + } + + this._visible = this._core.isVisible(); + this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval); + }; + + /** + * Refreshes the element. + */ + AutoRefresh.prototype.refresh = function() { + if (this._core.isVisible() === this._visible) { + return; + } + + this._visible = !this._visible; + + this._core.$element.toggleClass('owl-hidden', !this._visible); + + this._visible && (this._core.invalidate('width') && this._core.refresh()); + }; + + /** + * Destroys the plugin. + */ + AutoRefresh.prototype.destroy = function() { + var handler, property; + + window.clearInterval(this._interval); + + for (handler in this._handlers) { + this._core.$element.off(handler, this._handlers[handler]); + } + for (property in Object.getOwnPropertyNames(this)) { + typeof this[property] != 'function' && (this[property] = null); + } + }; + + $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh; + +})(window.Zepto || window.jQuery, window, document); + +/** + * Lazy Plugin + * @version 2.3.4 + * @author Bartosz Wojciechowski + * @author David Deutsch + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + + /** + * Creates the lazy plugin. + * @class The Lazy Plugin + * @param {Owl} carousel - The Owl Carousel + */ + var Lazy = function(carousel) { + + /** + * Reference to the core. + * @protected + * @type {Owl} + */ + this._core = carousel; + + /** + * Already loaded items. + * @protected + * @type {Array.} + */ + this._loaded = []; + + /** + * Event handlers. + * @protected + * @type {Object} + */ + this._handlers = { + 'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) { + if (!e.namespace) { + return; + } + + if (!this._core.settings || !this._core.settings.lazyLoad) { + return; + } + + if ((e.property && e.property.name == 'position') || e.type == 'initialized') { + var settings = this._core.settings, + n = (settings.center && Math.ceil(settings.items / 2) || settings.items), + i = ((settings.center && n * -1) || 0), + position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i, + clones = this._core.clones().length, + load = $.proxy(function(i, v) { this.load(v) }, this); + //TODO: Need documentation for this new option + if (settings.lazyLoadEager > 0) { + n += settings.lazyLoadEager; + // If the carousel is looping also preload images that are to the "left" + if (settings.loop) { + position -= settings.lazyLoadEager; + n++; + } + } + + while (i++ < n) { + this.load(clones / 2 + this._core.relative(position)); + clones && $.each(this._core.clones(this._core.relative(position)), load); + position++; + } + } + }, this) + }; + + // set the default options + this._core.options = $.extend({}, Lazy.Defaults, this._core.options); + + // register event handler + this._core.$element.on(this._handlers); + }; + + /** + * Default options. + * @public + */ + Lazy.Defaults = { + lazyLoad: false, + lazyLoadEager: 0 + }; + + /** + * Loads all resources of an item at the specified position. + * @param {Number} position - The absolute position of the item. + * @protected + */ + Lazy.prototype.load = function(position) { + var $item = this._core.$stage.children().eq(position), + $elements = $item && $item.find('.owl-lazy'); + + if (!$elements || $.inArray($item.get(0), this._loaded) > -1) { + return; + } + + $elements.each($.proxy(function(index, element) { + var $element = $(element), image, + url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset'); + + this._core.trigger('load', { element: $element, url: url }, 'lazy'); + + if ($element.is('img')) { + $element.one('load.owl.lazy', $.proxy(function() { + $element.css('opacity', 1); + this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); + }, this)).attr('src', url); + } else if ($element.is('source')) { + $element.one('load.owl.lazy', $.proxy(function() { + this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); + }, this)).attr('srcset', url); + } else { + image = new Image(); + image.onload = $.proxy(function() { + $element.css({ + 'background-image': 'url("' + url + '")', + 'opacity': '1' + }); + this._core.trigger('loaded', { element: $element, url: url }, 'lazy'); + }, this); + image.src = url; + } + }, this)); + + this._loaded.push($item.get(0)); + }; + + /** + * Destroys the plugin. + * @public + */ + Lazy.prototype.destroy = function() { + var handler, property; + + for (handler in this.handlers) { + this._core.$element.off(handler, this.handlers[handler]); + } + for (property in Object.getOwnPropertyNames(this)) { + typeof this[property] != 'function' && (this[property] = null); + } + }; + + $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy; + +})(window.Zepto || window.jQuery, window, document); + +/** + * AutoHeight Plugin + * @version 2.3.4 + * @author Bartosz Wojciechowski + * @author David Deutsch + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + + /** + * Creates the auto height plugin. + * @class The Auto Height Plugin + * @param {Owl} carousel - The Owl Carousel + */ + var AutoHeight = function(carousel) { + /** + * Reference to the core. + * @protected + * @type {Owl} + */ + this._core = carousel; + + this._previousHeight = null; + + /** + * All event handlers. + * @protected + * @type {Object} + */ + this._handlers = { + 'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.autoHeight) { + this.update(); + } + }, this), + 'changed.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.autoHeight && e.property.name === 'position'){ + this.update(); + } + }, this), + 'loaded.owl.lazy': $.proxy(function(e) { + if (e.namespace && this._core.settings.autoHeight + && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) { + this.update(); + } + }, this) + }; + + // set default options + this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options); + + // register event handlers + this._core.$element.on(this._handlers); + this._intervalId = null; + var refThis = this; + + // These changes have been taken from a PR by gavrochelegnou proposed in #1575 + // and have been made compatible with the latest jQuery version + $(window).on('load', function() { + if (refThis._core.settings.autoHeight) { + refThis.update(); + } + }); + + // Autoresize the height of the carousel when window is resized + // When carousel has images, the height is dependent on the width + // and should also change on resize + $(window).resize(function() { + if (refThis._core.settings.autoHeight) { + if (refThis._intervalId != null) { + clearTimeout(refThis._intervalId); + } + + refThis._intervalId = setTimeout(function() { + refThis.update(); + }, 250); + } + }); + + }; + + /** + * Default options. + * @public + */ + AutoHeight.Defaults = { + autoHeight: false, + autoHeightClass: 'owl-height' + }; + + /** + * Updates the view. + */ + AutoHeight.prototype.update = function() { + var start = this._core._current, + end = start + this._core.settings.items, + lazyLoadEnabled = this._core.settings.lazyLoad, + visible = this._core.$stage.children().toArray().slice(start, end), + heights = [], + maxheight = 0; + + $.each(visible, function(index, item) { + heights.push($(item).height()); + }); + + maxheight = Math.max.apply(null, heights); + + if (maxheight <= 1 && lazyLoadEnabled && this._previousHeight) { + maxheight = this._previousHeight; + } + + this._previousHeight = maxheight; + + this._core.$stage.parent() + .height(maxheight) + .addClass(this._core.settings.autoHeightClass); + }; + + AutoHeight.prototype.destroy = function() { + var handler, property; + + for (handler in this._handlers) { + this._core.$element.off(handler, this._handlers[handler]); + } + for (property in Object.getOwnPropertyNames(this)) { + typeof this[property] !== 'function' && (this[property] = null); + } + }; + + $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight; + +})(window.Zepto || window.jQuery, window, document); + +/** + * Video Plugin + * @version 2.3.4 + * @author Bartosz Wojciechowski + * @author David Deutsch + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + + /** + * Creates the video plugin. + * @class The Video Plugin + * @param {Owl} carousel - The Owl Carousel + */ + var Video = function(carousel) { + /** + * Reference to the core. + * @protected + * @type {Owl} + */ + this._core = carousel; + + /** + * Cache all video URLs. + * @protected + * @type {Object} + */ + this._videos = {}; + + /** + * Current playing item. + * @protected + * @type {jQuery} + */ + this._playing = null; + + /** + * All event handlers. + * @todo The cloned content removale is too late + * @protected + * @type {Object} + */ + this._handlers = { + 'initialized.owl.carousel': $.proxy(function(e) { + if (e.namespace) { + this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] }); + } + }, this), + 'resize.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.video && this.isInFullScreen()) { + e.preventDefault(); + } + }, this), + 'refreshed.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.is('resizing')) { + this._core.$stage.find('.cloned .owl-video-frame').remove(); + } + }, this), + 'changed.owl.carousel': $.proxy(function(e) { + if (e.namespace && e.property.name === 'position' && this._playing) { + this.stop(); + } + }, this), + 'prepared.owl.carousel': $.proxy(function(e) { + if (!e.namespace) { + return; + } + + var $element = $(e.content).find('.owl-video'); + + if ($element.length) { + $element.css('display', 'none'); + this.fetch($element, $(e.content)); + } + }, this) + }; + + // set default options + this._core.options = $.extend({}, Video.Defaults, this._core.options); + + // register event handlers + this._core.$element.on(this._handlers); + + this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) { + this.play(e); + }, this)); + }; + + /** + * Default options. + * @public + */ + Video.Defaults = { + video: false, + videoHeight: false, + videoWidth: false + }; + + /** + * Gets the video ID and the type (YouTube/Vimeo/vzaar only). + * @protected + * @param {jQuery} target - The target containing the video data. + * @param {jQuery} item - The item containing the video. + */ + Video.prototype.fetch = function(target, item) { + var type = (function() { + if (target.attr('data-vimeo-id')) { + return 'vimeo'; + } else if (target.attr('data-vzaar-id')) { + return 'vzaar' + } else { + return 'youtube'; + } + })(), + id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'), + width = target.attr('data-width') || this._core.settings.videoWidth, + height = target.attr('data-height') || this._core.settings.videoHeight, + url = target.attr('href'); + + if (url) { + + /* + Parses the id's out of the following urls (and probably more): + https://www.youtube.com/watch?v=:id + https://youtu.be/:id + https://vimeo.com/:id + https://vimeo.com/channels/:channel/:id + https://vimeo.com/groups/:group/videos/:id + https://app.vzaar.com/videos/:id + + Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F + */ + + id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/); + + if (id[3].indexOf('youtu') > -1) { + type = 'youtube'; + } else if (id[3].indexOf('vimeo') > -1) { + type = 'vimeo'; + } else if (id[3].indexOf('vzaar') > -1) { + type = 'vzaar'; + } else { + throw new Error('Video URL not supported.'); + } + id = id[6]; + } else { + throw new Error('Missing video URL.'); + } + + this._videos[url] = { + type: type, + id: id, + width: width, + height: height + }; + + item.attr('data-video', url); + + this.thumbnail(target, this._videos[url]); + }; + + /** + * Creates video thumbnail. + * @protected + * @param {jQuery} target - The target containing the video data. + * @param {Object} info - The video info object. + * @see `fetch` + */ + Video.prototype.thumbnail = function(target, video) { + var tnLink, + icon, + path, + dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '', + customTn = target.find('img'), + srcType = 'src', + lazyClass = '', + settings = this._core.settings, + create = function(path) { + icon = '
'; + + if (settings.lazyLoad) { + tnLink = $('
',{ + "class": 'owl-video-tn ' + lazyClass, + "srcType": path + }); + } else { + tnLink = $( '
', { + "class": "owl-video-tn", + "style": 'opacity:1;background-image:url(' + path + ')' + }); + } + target.after(tnLink); + target.after(icon); + }; + + // wrap video content into owl-video-wrapper div + target.wrap( $( '
', { + "class": "owl-video-wrapper", + "style": dimensions + })); + + if (this._core.settings.lazyLoad) { + srcType = 'data-src'; + lazyClass = 'owl-lazy'; + } + + // custom thumbnail + if (customTn.length) { + create(customTn.attr(srcType)); + customTn.remove(); + return false; + } + + if (video.type === 'youtube') { + path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg"; + create(path); + } else if (video.type === 'vimeo') { + $.ajax({ + type: 'GET', + url: '//vimeo.com/api/v2/video/' + video.id + '.json', + jsonp: 'callback', + dataType: 'jsonp', + success: function(data) { + path = data[0].thumbnail_large; + create(path); + } + }); + } else if (video.type === 'vzaar') { + $.ajax({ + type: 'GET', + url: '//vzaar.com/api/videos/' + video.id + '.json', + jsonp: 'callback', + dataType: 'jsonp', + success: function(data) { + path = data.framegrab_url; + create(path); + } + }); + } + }; + + /** + * Stops the current video. + * @public + */ + Video.prototype.stop = function() { + this._core.trigger('stop', null, 'video'); + this._playing.find('.owl-video-frame').remove(); + this._playing.removeClass('owl-video-playing'); + this._playing = null; + this._core.leave('playing'); + this._core.trigger('stopped', null, 'video'); + }; + + /** + * Starts the current video. + * @public + * @param {Event} event - The event arguments. + */ + Video.prototype.play = function(event) { + var target = $(event.target), + item = target.closest('.' + this._core.settings.itemClass), + video = this._videos[item.attr('data-video')], + width = video.width || '100%', + height = video.height || this._core.$stage.height(), + html, + iframe; + + if (this._playing) { + return; + } + + this._core.enter('playing'); + this._core.trigger('play', null, 'video'); + + item = this._core.items(this._core.relative(item.index())); + + this._core.reset(item.index()); + + html = $( '' ); + html.attr( 'height', height ); + html.attr( 'width', width ); + if (video.type === 'youtube') { + html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id ); + } else if (video.type === 'vimeo') { + html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' ); + } else if (video.type === 'vzaar') { + html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' ); + } + + iframe = $(html).wrap( '
' ).insertAfter(item.find('.owl-video')); + + this._playing = item.addClass('owl-video-playing'); + }; + + /** + * Checks whether an video is currently in full screen mode or not. + * @todo Bad style because looks like a readonly method but changes members. + * @protected + * @returns {Boolean} + */ + Video.prototype.isInFullScreen = function() { + var element = document.fullscreenElement || document.mozFullScreenElement || + document.webkitFullscreenElement; + + return element && $(element).parent().hasClass('owl-video-frame'); + }; + + /** + * Destroys the plugin. + */ + Video.prototype.destroy = function() { + var handler, property; + + this._core.$element.off('click.owl.video'); + + for (handler in this._handlers) { + this._core.$element.off(handler, this._handlers[handler]); + } + for (property in Object.getOwnPropertyNames(this)) { + typeof this[property] != 'function' && (this[property] = null); + } + }; + + $.fn.owlCarousel.Constructor.Plugins.Video = Video; + +})(window.Zepto || window.jQuery, window, document); + +/** + * Animate Plugin + * @version 2.3.4 + * @author Bartosz Wojciechowski + * @author David Deutsch + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + + /** + * Creates the animate plugin. + * @class The Navigation Plugin + * @param {Owl} scope - The Owl Carousel + */ + var Animate = function(scope) { + this.core = scope; + this.core.options = $.extend({}, Animate.Defaults, this.core.options); + this.swapping = true; + this.previous = undefined; + this.next = undefined; + + this.handlers = { + 'change.owl.carousel': $.proxy(function(e) { + if (e.namespace && e.property.name == 'position') { + this.previous = this.core.current(); + this.next = e.property.value; + } + }, this), + 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) { + if (e.namespace) { + this.swapping = e.type == 'translated'; + } + }, this), + 'translate.owl.carousel': $.proxy(function(e) { + if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) { + this.swap(); + } + }, this) + }; + + this.core.$element.on(this.handlers); + }; + + /** + * Default options. + * @public + */ + Animate.Defaults = { + animateOut: false, + animateIn: false + }; + + /** + * Toggles the animation classes whenever an translations starts. + * @protected + * @returns {Boolean|undefined} + */ + Animate.prototype.swap = function() { + + if (this.core.settings.items !== 1) { + return; + } + + if (!$.support.animation || !$.support.transition) { + return; + } + + this.core.speed(0); + + var left, + clear = $.proxy(this.clear, this), + previous = this.core.$stage.children().eq(this.previous), + next = this.core.$stage.children().eq(this.next), + incoming = this.core.settings.animateIn, + outgoing = this.core.settings.animateOut; + + if (this.core.current() === this.previous) { + return; + } + + if (outgoing) { + left = this.core.coordinates(this.previous) - this.core.coordinates(this.next); + previous.one($.support.animation.end, clear) + .css( { 'left': left + 'px' } ) + .addClass('animated owl-animated-out') + .addClass(outgoing); + } + + if (incoming) { + next.one($.support.animation.end, clear) + .addClass('animated owl-animated-in') + .addClass(incoming); + } + }; + + Animate.prototype.clear = function(e) { + $(e.target).css( { 'left': '' } ) + .removeClass('animated owl-animated-out owl-animated-in') + .removeClass(this.core.settings.animateIn) + .removeClass(this.core.settings.animateOut); + this.core.onTransitionEnd(); + }; + + /** + * Destroys the plugin. + * @public + */ + Animate.prototype.destroy = function() { + var handler, property; + + for (handler in this.handlers) { + this.core.$element.off(handler, this.handlers[handler]); + } + for (property in Object.getOwnPropertyNames(this)) { + typeof this[property] != 'function' && (this[property] = null); + } + }; + + $.fn.owlCarousel.Constructor.Plugins.Animate = Animate; + +})(window.Zepto || window.jQuery, window, document); + +/** + * Autoplay Plugin + * @version 2.3.4 + * @author Bartosz Wojciechowski + * @author Artus Kolanowski + * @author David Deutsch + * @author Tom De Caluwé + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + + /** + * Creates the autoplay plugin. + * @class The Autoplay Plugin + * @param {Owl} scope - The Owl Carousel + */ + var Autoplay = function(carousel) { + /** + * Reference to the core. + * @protected + * @type {Owl} + */ + this._core = carousel; + + /** + * The autoplay timeout id. + * @type {Number} + */ + this._call = null; + + /** + * Depending on the state of the plugin, this variable contains either + * the start time of the timer or the current timer value if it's + * paused. Since we start in a paused state we initialize the timer + * value. + * @type {Number} + */ + this._time = 0; + + /** + * Stores the timeout currently used. + * @type {Number} + */ + this._timeout = 0; + + /** + * Indicates whenever the autoplay is paused. + * @type {Boolean} + */ + this._paused = true; + + /** + * All event handlers. + * @protected + * @type {Object} + */ + this._handlers = { + 'changed.owl.carousel': $.proxy(function(e) { + if (e.namespace && e.property.name === 'settings') { + if (this._core.settings.autoplay) { + this.play(); + } else { + this.stop(); + } + } else if (e.namespace && e.property.name === 'position' && this._paused) { + // Reset the timer. This code is triggered when the position + // of the carousel was changed through user interaction. + this._time = 0; + } + }, this), + 'initialized.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.autoplay) { + this.play(); + } + }, this), + 'play.owl.autoplay': $.proxy(function(e, t, s) { + if (e.namespace) { + this.play(t, s); + } + }, this), + 'stop.owl.autoplay': $.proxy(function(e) { + if (e.namespace) { + this.stop(); + } + }, this), + 'mouseover.owl.autoplay': $.proxy(function() { + if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { + this.pause(); + } + }, this), + 'mouseleave.owl.autoplay': $.proxy(function() { + if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { + this.play(); + } + }, this), + 'touchstart.owl.core': $.proxy(function() { + if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) { + this.pause(); + } + }, this), + 'touchend.owl.core': $.proxy(function() { + if (this._core.settings.autoplayHoverPause) { + this.play(); + } + }, this) + }; + + // register event handlers + this._core.$element.on(this._handlers); + + // set default options + this._core.options = $.extend({}, Autoplay.Defaults, this._core.options); + }; + + /** + * Default options. + * @public + */ + Autoplay.Defaults = { + autoplay: false, + autoplayTimeout: 5000, + autoplayHoverPause: false, + autoplaySpeed: false + }; + + /** + * Transition to the next slide and set a timeout for the next transition. + * @private + * @param {Number} [speed] - The animation speed for the animations. + */ + Autoplay.prototype._next = function(speed) { + this._call = window.setTimeout( + $.proxy(this._next, this, speed), + this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read() + ); + + if (this._core.is('interacting') || document.hidden) { + return; + } + this._core.next(speed || this._core.settings.autoplaySpeed); + } + + /** + * Reads the current timer value when the timer is playing. + * @public + */ + Autoplay.prototype.read = function() { + return new Date().getTime() - this._time; + }; + + /** + * Starts the autoplay. + * @public + * @param {Number} [timeout] - The interval before the next animation starts. + * @param {Number} [speed] - The animation speed for the animations. + */ + Autoplay.prototype.play = function(timeout, speed) { + var elapsed; + + if (!this._core.is('rotating')) { + this._core.enter('rotating'); + } + + timeout = timeout || this._core.settings.autoplayTimeout; + + // Calculate the elapsed time since the last transition. If the carousel + // wasn't playing this calculation will yield zero. + elapsed = Math.min(this._time % (this._timeout || timeout), timeout); + + if (this._paused) { + // Start the clock. + this._time = this.read(); + this._paused = false; + } else { + // Clear the active timeout to allow replacement. + window.clearTimeout(this._call); + } + + // Adjust the origin of the timer to match the new timeout value. + this._time += this.read() % timeout - elapsed; + + this._timeout = timeout; + this._call = window.setTimeout($.proxy(this._next, this, speed), timeout - elapsed); + }; + + /** + * Stops the autoplay. + * @public + */ + Autoplay.prototype.stop = function() { + if (this._core.is('rotating')) { + // Reset the clock. + this._time = 0; + this._paused = true; + + window.clearTimeout(this._call); + this._core.leave('rotating'); + } + }; + + /** + * Pauses the autoplay. + * @public + */ + Autoplay.prototype.pause = function() { + if (this._core.is('rotating') && !this._paused) { + // Pause the clock. + this._time = this.read(); + this._paused = true; + + window.clearTimeout(this._call); + } + }; + + /** + * Destroys the plugin. + */ + Autoplay.prototype.destroy = function() { + var handler, property; + + this.stop(); + + for (handler in this._handlers) { + this._core.$element.off(handler, this._handlers[handler]); + } + for (property in Object.getOwnPropertyNames(this)) { + typeof this[property] != 'function' && (this[property] = null); + } + }; + + $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay; + +})(window.Zepto || window.jQuery, window, document); + +/** + * Navigation Plugin + * @version 2.3.4 + * @author Artus Kolanowski + * @author David Deutsch + * @license The MIT License (MIT) + */ +;(function($, window, document, undefined) { + 'use strict'; + + /** + * Creates the navigation plugin. + * @class The Navigation Plugin + * @param {Owl} carousel - The Owl Carousel. + */ + var Navigation = function(carousel) { + /** + * Reference to the core. + * @protected + * @type {Owl} + */ + this._core = carousel; + + /** + * Indicates whether the plugin is initialized or not. + * @protected + * @type {Boolean} + */ + this._initialized = false; + + /** + * The current paging indexes. + * @protected + * @type {Array} + */ + this._pages = []; + + /** + * All DOM elements of the user interface. + * @protected + * @type {Object} + */ + this._controls = {}; + + /** + * Markup for an indicator. + * @protected + * @type {Array.} + */ + this._templates = []; + + /** + * The carousel element. + * @type {jQuery} + */ + this.$element = this._core.$element; + + /** + * Overridden methods of the carousel. + * @protected + * @type {Object} + */ + this._overrides = { + next: this._core.next, + prev: this._core.prev, + to: this._core.to + }; + + /** + * All event handlers. + * @protected + * @type {Object} + */ + this._handlers = { + 'prepared.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.dotsData) { + this._templates.push('
' + + $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '
'); + } + }, this), + 'added.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.dotsData) { + this._templates.splice(e.position, 0, this._templates.pop()); + } + }, this), + 'remove.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._core.settings.dotsData) { + this._templates.splice(e.position, 1); + } + }, this), + 'changed.owl.carousel': $.proxy(function(e) { + if (e.namespace && e.property.name == 'position') { + this.draw(); + } + }, this), + 'initialized.owl.carousel': $.proxy(function(e) { + if (e.namespace && !this._initialized) { + this._core.trigger('initialize', null, 'navigation'); + this.initialize(); + this.update(); + this.draw(); + this._initialized = true; + this._core.trigger('initialized', null, 'navigation'); + } + }, this), + 'refreshed.owl.carousel': $.proxy(function(e) { + if (e.namespace && this._initialized) { + this._core.trigger('refresh', null, 'navigation'); + this.update(); + this.draw(); + this._core.trigger('refreshed', null, 'navigation'); + } + }, this) + }; + + // set default options + this._core.options = $.extend({}, Navigation.Defaults, this._core.options); + + // register event handlers + this.$element.on(this._handlers); + }; + + /** + * Default options. + * @public + * @todo Rename `slideBy` to `navBy` + */ + Navigation.Defaults = { + nav: false, + navText: [ + '‹', + '›' + ], + navSpeed: false, + navElement: 'button type="button" role="presentation"', + navContainer: false, + navContainerClass: 'owl-nav', + navClass: [ + 'owl-prev', + 'owl-next' + ], + slideBy: 1, + dotClass: 'owl-dot', + dotsClass: 'owl-dots', + dots: true, + dotsEach: false, + dotsData: false, + dotsSpeed: false, + dotsContainer: false + }; + + /** + * Initializes the layout of the plugin and extends the carousel. + * @protected + */ + Navigation.prototype.initialize = function() { + var override, + settings = this._core.settings; + + // create DOM structure for relative navigation + this._controls.$relative = (settings.navContainer ? $(settings.navContainer) + : $('
').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled'); + + this._controls.$previous = $('<' + settings.navElement + '>') + .addClass(settings.navClass[0]) + .html(settings.navText[0]) + .prependTo(this._controls.$relative) + .on('click', $.proxy(function(e) { + this.prev(settings.navSpeed); + }, this)); + this._controls.$next = $('<' + settings.navElement + '>') + .addClass(settings.navClass[1]) + .html(settings.navText[1]) + .appendTo(this._controls.$relative) + .on('click', $.proxy(function(e) { + this.next(settings.navSpeed); + }, this)); + + // create DOM structure for absolute navigation + if (!settings.dotsData) { + this._templates = [ $(' + + + +
+
+
+ @foreach($moviesByDepartments as $department => $movies) +
+

{{ $department }}

+
+ @foreach($movies as $movie) +
+
+ + {{ $movie->title }} + +
+
+ @endforeach + @endforeach +
+
+
+
+ @foreach($showsByDepartment as $department => $shows) +
+

{{ $department }}

+
+ @foreach($shows as $show) +
+
+ + {{ $show->name }} + +
+
+ @endforeach + @endforeach +
+
+
diff --git a/resources/views/forum/index.blade.php b/resources/views/forum/index.blade.php index 55fe916..2756371 100644 --- a/resources/views/forum/index.blade.php +++ b/resources/views/forum/index.blade.php @@ -35,7 +35,7 @@ i
last diff --git a/resources/views/forum/thread.blade.php b/resources/views/forum/thread.blade.php new file mode 100644 index 0000000..a494855 --- /dev/null +++ b/resources/views/forum/thread.blade.php @@ -0,0 +1,56 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
+
+

{{ $thread->name }}

+
+ +
+
+
+ {{ $thread->description }} +
+
+
+
+ @if($topics->count()) + topics + @else +
+ There are no topics at the moment! Go ahead, post the first one! +
+ @endif +
+
+
+
+ +
+
+
+
+@endsection diff --git a/resources/views/forum/topics/create.blade.php b/resources/views/forum/topics/create.blade.php new file mode 100644 index 0000000..77ab4eb --- /dev/null +++ b/resources/views/forum/topics/create.blade.php @@ -0,0 +1,37 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+ @csrf +
+ + +
+
+
+
+
+ +
+
+
+
+@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index d24bf1e..2bf3442 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -17,11 +17,16 @@ + + @vite(['resources/sass/app.scss', 'resources/js/app.js']) @livewireStyles +
+ 1 | 2 | 3 | 4 +
@include('layouts.header') diff --git a/resources/views/layouts/header.blade.php b/resources/views/layouts/header.blade.php index 3d2bd29..3118e0f 100644 --- a/resources/views/layouts/header.blade.php +++ b/resources/views/layouts/header.blade.php @@ -9,7 +9,7 @@
- {{ $movie->vote_average }}
- {{ $movie->vote_count }} votes + @if(isset($movie)) + {{ $movie->vote_average }}
+ {{ $movie->vote_count }} votes + @else + {{ $show->vote_average }}
+ {{ $show->vote_count }} votes + @endif
-
check() ? ($movie->ratingBy(auth()->user()) ? 'data-rating='.$movie->ratingBy(auth()->user()) : '') : '' }}>
+
check()) + @if(isset($movie)) + {{ $movie->ratingBy(auth()->user()) ? 'data-rating='.$movie->ratingBy(auth()->user()) : '' }} + @else + {{ $show->ratingBy(auth()->user()) ? 'data-rating='.$show->ratingBy(auth()->user()) : '' }} + @endif + @endif + > + +
diff --git a/resources/views/layouts/user_actions.blade.php b/resources/views/layouts/user_actions.blade.php new file mode 100644 index 0000000..66b6571 --- /dev/null +++ b/resources/views/layouts/user_actions.blade.php @@ -0,0 +1,23 @@ + diff --git a/resources/views/livewire/show-page/recommended.blade.php b/resources/views/livewire/show-page/recommended.blade.php new file mode 100644 index 0000000..756e83d --- /dev/null +++ b/resources/views/livewire/show-page/recommended.blade.php @@ -0,0 +1,32 @@ +
+ +
diff --git a/resources/views/livewire/show-page/similar.blade.php b/resources/views/livewire/show-page/similar.blade.php new file mode 100644 index 0000000..887c07c --- /dev/null +++ b/resources/views/livewire/show-page/similar.blade.php @@ -0,0 +1,32 @@ +
+ +
diff --git a/resources/views/livewire/show-page/tabs/cast.blade.php b/resources/views/livewire/show-page/tabs/cast.blade.php new file mode 100644 index 0000000..a6c54f5 --- /dev/null +++ b/resources/views/livewire/show-page/tabs/cast.blade.php @@ -0,0 +1,31 @@ +
+
+ @foreach($peopleByDepartment as $department => $personInfo) +
+ {{ $department }} +
+
+
+ @foreach($personInfo as [$person, $character]) +
+
+ @if($person->profile_path == null) + @if($person->gender == 2) + + @else + + @endif + @else + + @endif + {{ $person->name }}
+ {{ $character }} +
+
+ @endforeach +
+
+
+ @endforeach +
+
diff --git a/resources/views/livewire/show-page/tabs/crew.blade.php b/resources/views/livewire/show-page/tabs/crew.blade.php new file mode 100644 index 0000000..67506b7 --- /dev/null +++ b/resources/views/livewire/show-page/tabs/crew.blade.php @@ -0,0 +1,31 @@ +
+
+ @foreach($peopleByDepartment as $department => $personInfo) +
+ {{ $department }} +
+
+
+ @foreach($personInfo as [$person, $character]) +
+
+ @if($person->profile_path == null) + @if($person->gender == 2) + + @else + + @endif + @else + + @endif + {{ $person->name }}
+ {{ $character }} +
+
+ @endforeach +
+
+
+ @endforeach +
+
diff --git a/resources/views/livewire/show-page/tabs/details.blade.php b/resources/views/livewire/show-page/tabs/details.blade.php new file mode 100644 index 0000000..3ea6623 --- /dev/null +++ b/resources/views/livewire/show-page/tabs/details.blade.php @@ -0,0 +1,55 @@ +
+
+ Episode run time: + @if($show->episode_run_time) + {{ $show->episode_run_time }} minutes + @else + N/A + @endif +
+
+ First air date: {{ $show->first_air_date->format('jS \o\f F, Y') }} +
+ @if($show->last_air_date) +
+ Last air date: {{ $show->last_air_date->format('jS \o\f F, Y') }} +
+ @endif + @if($show->genres) +
+ Genres: + @foreach($show->genres as $genre) + {{ $genre->name }} + @endforeach +
+ @endif + @if($show->networks) +
+ Networks: + @foreach($show->networks as $network) + {{ $network->name }} + @endforeach +
+ @endif +
+ Seasons: {{ $show->number_of_seasons }} / + Episodes: {{ $show->number_of_episodes }} +
+
+ Status: {{ $show->status }} +
+
+ Languages: + @foreach((is_array($show->languages) ? $show->languages : json_decode($show->languages)) as $language) + {{ $language }}@if(!$loop->last), @endif + @endforeach +
+ @if($show->productionCompanies) +
+ Production companies: + @foreach($show->productionCompanies as $productionCompany) + {{ $productionCompany->name }} + @endforeach +
+ @endif +
diff --git a/resources/views/livewire/show-page/tabs/releases.blade.php b/resources/views/livewire/show-page/tabs/releases.blade.php new file mode 100644 index 0000000..15e5660 --- /dev/null +++ b/resources/views/livewire/show-page/tabs/releases.blade.php @@ -0,0 +1,3 @@ +
+ {{-- The whole world belongs to you. --}} +
diff --git a/resources/views/movie/index.blade.php b/resources/views/movie/index.blade.php index 4852c5c..21f19ba 100644 --- a/resources/views/movie/index.blade.php +++ b/resources/views/movie/index.blade.php @@ -15,7 +15,7 @@ {{ $movie->title }} diff --git a/resources/views/movie/show.blade.php b/resources/views/movie/show.blade.php index 23f7f25..b1171ea 100644 --- a/resources/views/movie/show.blade.php +++ b/resources/views/movie/show.blade.php @@ -6,7 +6,7 @@
-

{{ $movie->title }}

({{ $movie->release_date->format('Y') }}) +

{{ $movie->title }}

@if($movie->release_date)({{ $movie->release_date->format('Y') }})@endif
@@ -14,7 +14,7 @@ {{ $movie->title }} diff --git a/resources/views/profile/show.blade.php b/resources/views/profile/show.blade.php index 04458c4..cf22ec6 100644 --- a/resources/views/profile/show.blade.php +++ b/resources/views/profile/show.blade.php @@ -1,10 +1,68 @@ @extends('profile.profile') @section('page_content') +
-
- profile page +
+
+
Last watched
+
+
+
+
+
+
Stats
+
+ Last 30 Days/Watched
+ Shows — 4d 20h 24m (147 eps)
+ Movies — 0m
+
+ All Time/Watched
+ Shows — 297d 17h 23m (12,095 eps)
+ + Movies — 44d 15h 23m (568 movies) +
+
+
+
+
+
Featured list
+
+
+
+
+
+
+
+
Favourite
+
+
+
+
+
+
+ recently watched episodes +
+
+
+
+ recently watched movies +
+
+
+
+ most watched genres +
+
+
+
+ ratings graph +
+
+
+
+ comments
diff --git a/resources/views/show/index.blade.php b/resources/views/show/index.blade.php new file mode 100644 index 0000000..010a26b --- /dev/null +++ b/resources/views/show/index.blade.php @@ -0,0 +1,67 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
+ Shows +
+
+
+ @foreach($shows as $show) +
+
+ + {{ $show->name }} + + +
+
+ @endforeach +
+
+
+ {{ $shows->links() }} +
+
+
+ +
+
+
+
+@endsection diff --git a/resources/views/show/show.blade.php b/resources/views/show/show.blade.php new file mode 100644 index 0000000..bd4c7fd --- /dev/null +++ b/resources/views/show/show.blade.php @@ -0,0 +1,168 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+ +
+
+
+ + {{ $show->name }} + + +
+ @foreach($show->watchProviders as $watchProvider) + {{ $watchProvider->provider_name }} + @endforeach +
+ + view trailer +
+ @if($show->externalIds && $show->externalIds->tmdb_id) + + + + @endif + @if($show->externalIds && $show->externalIds->imdb_id) + + + + @endif + @if($show->externalIds && $show->externalIds->wikidata_id) + + + + @endif + @if($show->externalIds && $show->externalIds->tvdb_id) + + + + @endif +
+ + @if($show->homepage) +
+ Homepage +
+ @endif +
+
+ + Directed by + + +
{{ $show->tagline }}
+
{{ $show->overview }}
+
+ + +
+
+ @livewire(App\Livewire\ShowPage\Tabs\Details::class, ['show' => $show]) +
+
+ @livewire(App\Livewire\ShowPage\Tabs\Cast::class, ['show' => $show]) +
+
+ @livewire(App\Livewire\ShowPage\Tabs\Crew::class, ['show' => $show]) +
+
+ @livewire(App\Livewire\ShowPage\Tabs\Releases::class, ['show' => $show]) +
+
+
+
+
+ @if($show->images) +
+
+ +
+
+ @endif +
+
+
+
+ Similar +
+
+ +
+
+
+
+ @livewire(App\Livewire\ShowPage\Similar::class, ['show' => $show]) +
+
+
+
Recommended
+
+ @livewire(App\Livewire\ShowPage\Recommended::class, ['show' => $show]) +
+
+
+
Write review
+
+
+ @foreach($comments as $comment) +
+
+ @if($comment->author_avatar) + + @endif + {{ $comment->author_name }} + + {{ $comment->author_rating }} + + + + {{ $comment->published_at }} + + +
+
+ {!! $comment->content !!} +
+
+ @endforeach +
+
+
+ @include('layouts.user_actions') +
+
+
+
+@endsection diff --git a/routes/web.php b/routes/web.php index ba09544..c61dd78 100644 --- a/routes/web.php +++ b/routes/web.php @@ -16,6 +16,11 @@ Route::prefix('movies')->group(function () { Route::get('/{slug}', [\App\Http\Controllers\MovieController::class, 'show'])->name('movie.show'); }); +Route::prefix('shows')->group(function () { + Route::get('/', [\App\Http\Controllers\ShowController::class, 'index'])->name('show.index'); + Route::get('/{slug}', [\App\Http\Controllers\ShowController::class, 'show'])->name('show.show'); +}); + Route::prefix('celebrities')->group(function () { Route::get('/', [\App\Http\Controllers\CelebrityController::class, 'index'])->name('celebrity.index'); Route::get('/{slug}', [\App\Http\Controllers\CelebrityController::class, 'show'])->name('celebrity.show'); @@ -23,6 +28,8 @@ Route::prefix('celebrities')->group(function () { Route::prefix('forums')->group(function () { Route::get('/', [\App\Http\Controllers\Forum\CategoriesController::class, 'index'])->name('forums.index'); + Route::get('/{categorySlug}/{threadSlug}', [\App\Http\Controllers\Forum\ThreadsController::class, 'show'])->name('forums.thread.index'); + Route::get('/{categorySlug}/{threadSlug}/topic', [\App\Http\Controllers\Forum\TopicsController::class, 'create'])->name('forums.thread.topics.create'); }); Route::prefix('lists')->group(function () {