diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 00000000..f625c9d2
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,16 @@
+FROM mcr.microsoft.com/devcontainers/base:ubuntu
+
+# Node v22 setup - refer to below URL for details
+# https://github.com/nodesource/distributions?tab=readme-ov-file#using-ubuntu-nodejs-20
+RUN apt-get install -y curl \
+ && curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh \
+ && bash nodesource_setup.sh \
+ && apt-get install -y nodejs python3-setuptools \
+ && node -v # verify Node installation
+
+# Ghost setup
+RUN npm install ghost-cli@latest -g
+USER vscode
+RUN mkdir ~/ghost \
+ && cd ~/ghost \
+ && ghost install local
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 00000000..987389ca
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,28 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
+{
+ "name": "Ubuntu 24.04 w/ Ghost",
+ // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
+ "build": { "dockerfile": "Dockerfile" },
+
+ // Features to add to the dev container. More info: https://containers.dev/features.
+ // "features": {},
+
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
+ "forwardPorts": [2368],
+
+ "containerEnv": {
+ "REPO": "/workspaces/dawn-advisory-theme"
+ },
+
+ // Use 'postCreateCommand' to run commands after the container is created.
+ "postCreateCommand": "$REPO/.devcontainer/ghost_setup.sh",
+ "postStartCommand": "npm run prepare && cd ~/ghost && ghost start",
+ "postAttachCommand": "npm run dev"
+
+ // Configure tool-specific properties.
+ // "customizations": {},
+
+ // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+ // "remoteUser": "root"
+}
diff --git a/.devcontainer/ghost_setup.sh b/.devcontainer/ghost_setup.sh
new file mode 100755
index 00000000..6481e912
--- /dev/null
+++ b/.devcontainer/ghost_setup.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+export REPO="/workspaces/dawn-advisory-theme"
+
+# Step 1: Create symbolic link to theme
+ln -s $REPO ~/ghost/content/themes
+
+# Step 2: Start Ghost
+cd ~/ghost
+ghost start
+
+# Step 3: Install dependencies + run setup script
+cd $REPO/.devcontainer/ghost_setup
+npm install && npm start
diff --git a/.devcontainer/ghost_setup/index.js b/.devcontainer/ghost_setup/index.js
new file mode 100644
index 00000000..56efb113
--- /dev/null
+++ b/.devcontainer/ghost_setup/index.js
@@ -0,0 +1,52 @@
+const readline = require("readline");
+const GhostAdminAPI = require("@tryghost/admin-api");
+
+const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ prompt: "> ",
+});
+
+console.log("---");
+console.log("Please do the following steps:");
+console.log("Step 1: Complete the setup at http://localhost:2368/ghost/.");
+console.log(
+ "The actual details don't matter, but make sure to save your username and password.",
+);
+console.log(
+ "Step 2: Follow https://ghost.org/docs/admin-api/#token-authentication to create an integration.",
+);
+console.log("Step 3: Copy the Admin API key into the following prompt.");
+console.log("---");
+
+(async () => {
+ const apiKey = await new Promise((callback) => {
+ rl.question("Admin API Key: ", callback);
+ });
+
+ const api = new GhostAdminAPI({
+ url: "http://localhost:2368",
+ version: "v5.0",
+ key: apiKey,
+ });
+
+ console.log("Activating repository theme...");
+ await api.themes.activate("dawn-advisory-theme").then((res) => {
+ console.log(JSON.stringify(res));
+ });
+ console.log("Finished setup!");
+
+ console.log("---");
+ console.log("The remaining steps need to be done manually:");
+ console.log(
+ "1. Under Settings > Advanced > Import/Export, import an export of the main Ghost website.",
+ );
+ console.log("2. Under Settings > Labs, import redirects and routes.");
+ console.log("For more details, please reach out to the maintainers! :)");
+ console.log("---");
+
+ await new Promise((callback) => {
+ rl.question("Press enter to continue...", callback);
+ });
+ rl.close();
+})();
diff --git a/.devcontainer/ghost_setup/package.json b/.devcontainer/ghost_setup/package.json
new file mode 100644
index 00000000..a150f2b2
--- /dev/null
+++ b/.devcontainer/ghost_setup/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "ghost_setup",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "start": "node index.js"
+ },
+ "author": "",
+ "license": "MIT",
+ "description": "",
+ "dependencies": {
+ "@tryghost/admin-api": "^1.14.0"
+ }
+}
diff --git a/.djlintrc b/.djlintrc
new file mode 100644
index 00000000..36ed4d6b
--- /dev/null
+++ b/.djlintrc
@@ -0,0 +1,5 @@
+{
+ "profile": "handlebars",
+ "extension": "hbs",
+ "ignore": "H006,H013,H017,H021,H030,H031"
+}
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 2e22d271..ff2770ef 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,9 +1,27 @@
version: 2
updates:
- - package-ecosystem: npm
+ - package-ecosystem: "npm"
directory: "/"
schedule:
- interval: weekly
- reviewers:
- - "AdvisorySG/ghost-reviewers"
- open-pull-requests-limit: 4
+ interval: "weekly"
+ groups:
+ production-dependencies:
+ dependency-type: "production"
+ development-dependencies:
+ dependency-type: "development"
+
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ groups:
+ all-dependencies:
+ patterns: ["*"]
+
+ - package-ecosystem: "devcontainers"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ groups:
+ all-dependencies:
+ patterns: ["*"]
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 870a5fda..f6adc5ef 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -3,23 +3,37 @@ on:
pull_request:
push:
jobs:
+ pre_build:
+ continue-on-error: true
+ runs-on: ubuntu-24.04
+ outputs:
+ should_skip: ${{ steps.skip_check.outputs.should_skip }}
+ steps:
+ - id: skip_check
+ uses: fkirc/skip-duplicate-actions@v4
+ with:
+ concurrent_skipping: "same_content_newer"
+ paths_ignore: '["CONTRIBUTING.md", "LICENSE", "**/README.md"]'
+
build:
+ needs: pre_build
+ if: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || needs.pre_build.outputs.should_skip != 'true' }}
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [16.x]
+ node-version: [22.x]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Cache Node modules
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Setup Node
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
@@ -30,7 +44,7 @@ jobs:
- run: unzip dist/dawn-advisory-theme.zip -d dist/
- run: rm dist/dawn-advisory-theme.zip
- name: Upload build
- uses: actions/upload-artifact@v1
+ uses: actions/upload-artifact@v4
with:
name: dawn-advisory-theme-${{ github.sha }}
path: dist/
@@ -41,19 +55,19 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [16.x]
+ node-version: [22.x]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- name: Cache Node modules
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Setup Node
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
@@ -61,7 +75,7 @@ jobs:
- run: npm run zip
- name: Deploy Ghost theme
- uses: TryGhost/action-deploy-theme@v1.4.1
+ uses: TryGhost/action-deploy-theme@v1.6.6
with:
api-url: ${{ secrets.GHOST_API_URL }}
api-key: ${{ secrets.GHOST_DEPLOY_THEME_ADMIN_API_KEY }}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 6c4fb05e..ea16f355 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -4,10 +4,10 @@ on:
push:
jobs:
lint:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-24.04
strategy:
matrix:
- node-version: [16.x]
+ node-version: [22.x]
steps:
- uses: actions/checkout@v2
@@ -22,7 +22,14 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: 3.11
- run: npm install
+ - run: pip install djlint
+
- run: npx eslint .
- run: npx prettier -c .
+ - run: djlint . --lint
diff --git a/.gitignore b/.gitignore
index d4eedcc0..e2539788 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@ dist/
config.json
changelog.md
changelog.md.bk
+
+replit.nix
+.replit
\ No newline at end of file
diff --git a/README.md b/README.md
index 7166f25a..0ac9159e 100644
--- a/README.md
+++ b/README.md
@@ -22,29 +22,12 @@ npm run zip
4. Upload the zipfile at `dist/dawn-advisory-theme.zip` onto your local Ghost instance at `Settings > Theme > Change theme > Upload theme`.
-Optionally, if you have access to the [Admin panel of Advisory](https://beta.advisory.sg/ghost/), you can go to `Settings > Labs > Migration Options > Export your content` in order to export the posts and settings used for the actual website as a JSON file. This file can be imported into your local instance of Ghost, at `Settings > Labs > Migration Options > Import content`. Take note that this will not remove existing posts/pages.
+For new developers, please ask Tech Management for the posts and settings to be exported, and to pass you the output JSON file.
+This file can be imported into your local instance of Ghost, at `Settings > Labs > Migration Options > Import content`. Take note that this will not remove existing posts/pages.
-# Search
+Optionally, if you have access to the [Admin panel of Advisory](https://beta.advisory.sg/ghost/), you can go to `Settings > Labs > Migration Options > Export your content` in order to export the posts and settings used for the actual website as a JSON file.
-1. Navigate to the `Integrations` and click on `Add custom integration`.
-2. Copy the content API key; this will be used to fetch posts from your site.
-3. Insert the generated key in `Settings > Design > Site-wide > Content API key for search".
-
-The theme generates an index of posts for highly performant search. The index is updated automatically when posts are added or updated. However, it isn't updated when posts are unpublished or deleted.
-
-To force update the index, increment the search index migration version like `'v2'`.
-
-## Disable Content Search
-
-When your site has lots of posts, including the post content in the index cache ends up with exceeding the browser local storage quota. In that case, disabling content search is recommended. Also make sure increase the migration version to force update the old index.
-
-```html
-
-```
+Furthermore, also make sure to setup `routes.yaml` as explained further down below
# Dropdown Menu
@@ -88,6 +71,24 @@ For the homepage and separate [Stories](https://beta.advisory.sg/stories) page t
**Note**: The `routes.yaml` file supplied in the repository is not automatically deployed onto the main website.
+# Typesense Search
+
+The `/events/` and `/interviews/` pages have a typo-tolerant search box backed by [Typesense](https://typesense.org/), and the bottom-of-article "you might also like" widget uses Typesense for content-relevance ranking. Three settings live under `config.custom` in `package.json` and are admin-overridable in **Ghost Admin -> Settings -> Design -> Customize**:
+
+| Setting | Default | What it is |
+| ---------------------- | ------------------------------- | ------------------------------------------------------------------ |
+| `typesense_host` | `https://typesense.advisory.sg` | Typesense host URL (no trailing slash). HTTPS recommended. |
+| `typesense_api_key` | (Advisory SG search-only key) | Typesense **search-only** API key. Embedded client-side by design. |
+| `typesense_collection` | `ghost` | Name of the indexed Ghost-posts collection on the Typesense host. |
+
+The flow is: `package.json` defaults → `default.hbs` injects them as `window.__TYPESENSE_CONFIG__` → `assets/js/typesense-search.js` reads from that global at search time, falling back to the same defaults if the global is missing.
+
+**About the API key in source.** Typesense splits keys into _admin_ (read/write, secret) and _search-only_ (read-only, scoped to a collection). The search-only key is the analogue of Ghost's Content API key — it's designed to ship in client-side JavaScript and only grants read access to data that's already public. Don't paste an admin key here.
+
+**Deploying to a different Ghost instance.** If your instance points at a different Typesense backend, override the three settings in **Design → Customize** rather than editing the theme. The defaults in `package.json` are only the fallback for installs that don't override.
+
+**About the indexer.** This theme expects an existing Typesense collection populated with Ghost posts (`title`, `slug`, `excerpt`, `plaintext`, `feature_image`, `url`, `tags.name`, `tags.slug`, `published_at`, etc.). The sync mechanism (e.g. [MagicPages' Ghost-Typesense integration](https://github.com/magicpages/ghost-typesense)) is **not** part of this theme.
+
# PostCSS Features Used
- Autoprefixer - Don't worry about writing browser prefixes of any kind, it's all done automatically with support for the latest 2 major versions of every browser.
diff --git a/assets/css/blog/featured.css b/assets/css/blog/featured.css
index f99e62d9..55e2359b 100644
--- a/assets/css/blog/featured.css
+++ b/assets/css/blog/featured.css
@@ -1,23 +1,23 @@
.featured-wrapper {
- margin-top: 6rem;
-}
-
-.featured-wrapper .u-placeholder {
- margin-bottom: 3rem;
+ margin-bottom: 6rem;
}
.featured-wrapper .post-title {
margin-bottom: 0;
- font-size: 1.8rem;
+ font-size: 3.2rem;
font-weight: 700;
}
+.featured-track {
+ align-items: center;
+}
+
.has-serif-title .featured-wrapper .post-title {
font-family: var(--font-serif);
}
.featured-title {
- margin-bottom: 4.5rem;
+ margin-bottom: 1rem;
padding-bottom: 1rem;
border-bottom: 1px solid var(--light-gray-color);
color: var(--brand-color);
@@ -25,3 +25,30 @@
letter-spacing: 0.05rem;
text-transform: uppercase;
}
+
+.slide-content {
+ display: flex;
+ align-items: center;
+}
+
+.slide-image {
+ width: 50%;
+ flex-shrink: 0;
+ margin-right: 20px;
+ margin-top: 20px;
+ margin-left: 20px;
+}
+
+@media (max-width: 767px) {
+ .slide-image {
+ width: 100%;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+}
+
+@media (min-width: 768px) {
+ .featured-wrapper .u-placeholder {
+ margin-bottom: 3rem;
+ }
+}
diff --git a/assets/css/blog/navigation.css b/assets/css/blog/navigation.css
index 4d9003d9..73858342 100644
--- a/assets/css/blog/navigation.css
+++ b/assets/css/blog/navigation.css
@@ -16,3 +16,19 @@
width: 30px;
height: 30px;
}
+
+.navigation .navigation-icon {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+}
+
+.navigation {
+ position: relative;
+ height: 0;
+ width: 43px;
+ padding: 0;
+ padding-bottom: 43px;
+}
diff --git a/assets/css/blog/quotes.css b/assets/css/blog/quotes.css
new file mode 100644
index 00000000..65b62e6e
--- /dev/null
+++ b/assets/css/blog/quotes.css
@@ -0,0 +1,6 @@
+.glide__bullet {
+ background-color: rgba(0, 0, 0, 0.26);
+}
+.glide__bullet--active {
+ background-color: rgb(0 0 0);
+}
diff --git a/assets/css/blog/share.css b/assets/css/blog/share.css
index 2e0ae356..c781da25 100644
--- a/assets/css/blog/share.css
+++ b/assets/css/blog/share.css
@@ -23,11 +23,10 @@
}
.share-link .icon-facebook {
- margin-right: 0.3rem;
margin-left: -0.3rem;
}
-.share-link .icon-twitter {
+.share-link .icon-x {
margin-right: 0.3rem;
margin-left: -0.3rem;
}
@@ -41,8 +40,8 @@
background-color: var(--facebook-color);
}
-.share-link-twitter {
- background-color: var(--twitter-color);
+.share-link-x {
+ background-color: var(--x-color);
}
.share-link-linkedin {
diff --git a/assets/css/blog/single.css b/assets/css/blog/single.css
index a8930def..5d3e928e 100644
--- a/assets/css/blog/single.css
+++ b/assets/css/blog/single.css
@@ -4,11 +4,23 @@
}
.single-meta {
- margin-bottom: 1rem;
+ margin-bottom: 2rem;
color: var(--secondary-text-color);
- font-size: 1.2rem;
+ font-size: 1.5rem;
+ line-height: 2rem;
font-weight: 800;
text-transform: uppercase;
+ padding: 1.5rem;
+
+}
+
+.single-meta-date {
+ font-size: 1.5rem;
+
+}
+
+.single-meta-length {
+ font-size: 1.5rem;
}
.single-meta-item + .single-meta-item::before {
@@ -19,11 +31,13 @@
.single-meta-tag .post-tag {
color: var(--brand-color);
+ position: relative;
+ z-index: 2;
}
.single-title {
margin-bottom: 0;
- font-size: 4rem;
+ font-size: 3.75rem;
line-height: 1.2;
letter-spacing: -0.1rem;
}
@@ -42,7 +56,6 @@
}
.single-media {
- margin-top: 3rem;
margin-bottom: 3rem;
}
@@ -101,10 +114,6 @@
font-size: 1.8rem;
}
-.single-footer-bottom {
- margin-top: 2rem;
-}
-
@media (max-width: 767px) {
.single-header {
margin-bottom: 1.5rem;
@@ -122,3 +131,12 @@
margin-top: 3rem;
}
}
+
+.stretch-link {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ z-index: 1;
+}
diff --git a/assets/css/blog/tag.css b/assets/css/blog/tag.css
index b2f4f3cd..f279f823 100644
--- a/assets/css/blog/tag.css
+++ b/assets/css/blog/tag.css
@@ -14,28 +14,11 @@
max-width: 500px;
}
-.tag-list {
- margin-top: 2rem;
- font-weight: 700;
-}
-
-.tag-list-label {
- color: var(--secondary-text-color);
-}
-
-.tag-list-item:not(:last-child):after {
- content: ", ";
-}
-
-.tag-list-item {
- color: var(--brand-color);
-}
-
-.tag-media {
+.tag-feature-media {
margin-top: 4.5rem;
}
-.tag-media::before {
+.tag-feature-media::before {
padding-bottom: 35% !important;
}
@@ -44,7 +27,7 @@
margin-bottom: 2.5rem;
}
- .tag-media {
+ .tag-feature-media {
margin-top: 3rem;
}
}
diff --git a/assets/css/blog/team.css b/assets/css/blog/team.css
new file mode 100644
index 00000000..8853585c
--- /dev/null
+++ b/assets/css/blog/team.css
@@ -0,0 +1,31 @@
+.parent {
+ text-align: center;
+}
+
+.gallery {
+ margin-left: auto;
+ margin-right: auto;
+ border: 0px;
+ width: 240px;
+ display: inline-block;
+}
+
+.gallery img {
+ width: 100%;
+ height: auto;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.desc {
+ padding: 15px;
+ text-align: center;
+ font-weight: normal;
+}
+
+.desc::first-line {
+ font-weight: bold;
+}
+.page-header {
+ text-align: center;
+}
diff --git a/assets/css/general/basics.css b/assets/css/general/basics.css
index f1f2073e..94e07ab3 100644
--- a/assets/css/general/basics.css
+++ b/assets/css/general/basics.css
@@ -13,7 +13,7 @@
--orange-color: #ffc107;
--red-color: #dc3545;
--facebook-color: #3b5998;
- --twitter-color: #1da1f2;
+ --x-color: #000;
--linkedin-color: #0288d1;
--animation-base: ease-in-out;
--font-base: Mulish, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica,
@@ -35,7 +35,13 @@ html {
box-sizing: inherit;
}
+footer {
+ background: var(--black-color);
+ color: var(--white-color);
+}
+
body {
+ background: var(--black-color);
color: var(--primary-text-color);
font-family: var(--font-base);
font-size: 1.5rem;
diff --git a/assets/css/misc/kg.css b/assets/css/misc/kg.css
index 395fdb56..bb8260ce 100644
--- a/assets/css/misc/kg.css
+++ b/assets/css/misc/kg.css
@@ -1,6 +1,22 @@
+.kg-gallery-card,
+.kg-gallery-card * {
+ box-sizing: border-box;
+}
+
+.kg-gallery-card,
+.kg-image-card {
+ --gap: 1.2rem;
+}
+
+.kg-image-card:not(.kg-card-hascaption) + .kg-image-card,
+.kg-image-card:not(.kg-card-hascaption) + .kg-gallery-card,
+.kg-gallery-card:not(.kg-card-hascaption) + .kg-image-card,
+.kg-gallery-card:not(.kg-card-hascaption) + .kg-gallery-card {
+ margin-top: var(--gap);
+}
+
.kg-gallery-container {
- display: flex;
- flex-direction: column;
+ position: relative;
}
.kg-gallery-row {
@@ -9,21 +25,26 @@
justify-content: center;
}
-.kg-gallery-image {
- cursor: pointer;
-}
-
.kg-gallery-image img {
+ display: block;
+ margin: 0;
width: 100%;
height: 100%;
}
.kg-gallery-row:not(:first-of-type) {
- margin: 10px 0 0;
+ margin: var(--gap) 0 0;
}
.kg-gallery-image:not(:first-of-type) {
- margin: 0 0 0 10px;
+ margin: 0 0 0 var(--gap);
+}
+
+@media (max-width: 600px) {
+ .kg-gallery-card,
+ .kg-image-card {
+ --gap: 0.6rem;
+ }
}
.kg-bookmark-card {
diff --git a/assets/css/misc/utils.css b/assets/css/misc/utils.css
index 0ad56db9..733fc2ad 100644
--- a/assets/css/misc/utils.css
+++ b/assets/css/misc/utils.css
@@ -8,7 +8,7 @@
}
.u-text-format > * + * {
- margin-top: 3rem;
+ margin-top: 1rem;
}
.u-text-format > *:first-child {
@@ -22,7 +22,7 @@
}
.u-text-format > [id] {
- margin-top: 4rem;
+ margin-top: 2rem;
}
.u-text-format > [id] + p {
@@ -155,3 +155,7 @@
height: 100%;
object-fit: cover;
}
+
+[x-cloak] {
+ display: none !important;
+}
diff --git a/assets/css/screen.css b/assets/css/screen.css
index 8aaf3a0a..db1a0aea 100644
--- a/assets/css/screen.css
+++ b/assets/css/screen.css
@@ -16,6 +16,8 @@
@import "site/modal.css";
@import "site/search.css";
@import "site/burger.css";
+@import "site/dropdown.css";
+@import "site/footnotes.css";
@import "blog/feed.css";
@import "blog/featured.css";
@import "blog/pagination.css";
@@ -26,17 +28,18 @@
@import "blog/related.css";
@import "blog/comment.css";
@import "blog/tag.css";
+@import "blog/quotes.css";
@import "members/plan.css";
@import "members/auth.css";
@import "members/account.css";
@import "members/notification.css";
-@import "vendor/owl.css";
-@import "vendor/pswp.css";
@import "misc/lazyload.css";
@import "misc/kg.css";
@import "misc/utils.css";
@import "misc/animations.css";
+@import "../../node_modules/@glidejs/glide/dist/css/glide.core.min.css";
+
@layer base {
ul {
list-style: disc;
diff --git a/assets/css/site/dropdown.css b/assets/css/site/dropdown.css
new file mode 100644
index 00000000..8b2218d6
--- /dev/null
+++ b/assets/css/site/dropdown.css
@@ -0,0 +1,13 @@
+.dropdown-content {
+ padding: 10px;
+ margin: 5px 0;
+}
+
+.dropdown-header {
+ cursor: pointer;
+ padding: 10px;
+}
+
+.arrow-icon {
+ padding-right: 10px;
+}
diff --git a/assets/css/site/footer.css b/assets/css/site/footer.css
index f5db43fe..1fd02753 100644
--- a/assets/css/site/footer.css
+++ b/assets/css/site/footer.css
@@ -72,3 +72,7 @@
.theme-text {
margin-left: 0.3rem;
}
+
+.footer-text {
+ color: white;
+}
diff --git a/assets/css/site/footnotes.css b/assets/css/site/footnotes.css
new file mode 100644
index 00000000..5ff6d5b2
--- /dev/null
+++ b/assets/css/site/footnotes.css
@@ -0,0 +1,35 @@
+hr.footnotes-sep {
+ display: none;
+}
+
+section.footnotes ol {
+ list-style: none;
+ counter-reset: footnote-counter;
+}
+
+section.footnotes ol li {
+ counter-increment: footnote-counter;
+ position: relative;
+}
+
+section.footnotes ol li::before {
+ content: "[" counter(footnote-counter) "]";
+ font-weight: 700;
+ position: absolute;
+ left: -1.2em;
+ color: var(--brand-color);
+ font-weight: bold;
+}
+
+section.footnotes p {
+ padding-left: 0.5em;
+}
+
+section.footnotes a {
+ color: var(--brand-color);
+ text-decoration: none;
+}
+
+section.footnotes a:hover {
+ text-decoration: underline;
+}
diff --git a/assets/css/site/header.css b/assets/css/site/header.css
index 06278ef1..78f288a5 100644
--- a/assets/css/site/header.css
+++ b/assets/css/site/header.css
@@ -52,6 +52,7 @@
.menu-item {
margin: 0 1.5rem;
font-weight: 700;
+ white-space: nowrap;
}
.menu-item[href*="..."],
diff --git a/assets/css/site/layout.css b/assets/css/site/layout.css
index 2902a8a4..8a1f6187 100644
--- a/assets/css/site/layout.css
+++ b/assets/css/site/layout.css
@@ -6,11 +6,4 @@
.site-content {
flex-grow: 1;
- padding: 6rem 0;
-}
-
-@media (max-width: 767px) {
- .site-content {
- padding: 3rem 0;
- }
}
diff --git a/assets/css/site/modal.css b/assets/css/site/modal.css
index 3de1afb1..2f7185d0 100644
--- a/assets/css/site/modal.css
+++ b/assets/css/site/modal.css
@@ -23,7 +23,9 @@
}
.modal-search {
- width: 500px;
+ width: 60%;
+ height: 80%;
+ position: relative;
}
.modal-search .form-wrapper {
diff --git a/assets/css/site/search.css b/assets/css/site/search.css
index ece7f521..2b685e1a 100644
--- a/assets/css/site/search.css
+++ b/assets/css/site/search.css
@@ -16,23 +16,41 @@
}
.search-result {
- overflow-y: scroll;
- max-height: 50vh;
-webkit-overflow-scrolling: touch;
+ max-height: 70vh;
}
.search-result-row + .search-result-row {
border-top: 1px solid var(--light-gray-color);
}
+.search-result-text {
+ font-size: 1.5rem;
+}
+
.search-result-row-link {
display: block;
padding: 1.3rem 1.5rem 1.2rem;
- font-size: 1.5rem;
+ font-size: 1.8rem;
line-height: 1.4;
+ height: 100%;
+ overflow: hidden;
}
-.search-result-row-link:hover {
+.search-result-row-link:hover,
+.search-result-row-link:focus {
background-color: var(--lighter-gray-color);
opacity: 1;
}
+
+.search-prev:disabled {
+ background: #f5f5f5;
+ color: #c3c3c3;
+ outline: auto;
+}
+
+.search-next:disabled {
+ background: #f5f5f5;
+ color: #c3c3c3;
+ outline: auto;
+}
diff --git a/assets/css/site/sticky.css b/assets/css/site/sticky.css
index 0f7fa913..817021bb 100644
--- a/assets/css/site/sticky.css
+++ b/assets/css/site/sticky.css
@@ -32,7 +32,7 @@
left: 0;
width: 100%;
height: 2px;
- background-color: var(--light-gray-color);
+ background-color: var(--brand-color);
}
.sticky-progress {
@@ -48,7 +48,7 @@
@media (max-width: 767px) {
.sticky-title {
- font-size: 1.4rem;
+ font-size: 1.7rem;
font-weight: 700;
}
}
diff --git a/assets/css/vendor/owl.css b/assets/css/vendor/owl.css
deleted file mode 100644
index d6797f0d..00000000
--- a/assets/css/vendor/owl.css
+++ /dev/null
@@ -1,151 +0,0 @@
-.owl {
- display: none;
- position: relative;
- -webkit-tap-highlight-color: transparent;
- width: 100%;
- z-index: 1;
-}
-
-.owl .owl-stage {
- position: relative;
- touch-action: pan-y;
-}
-
-.owl .owl-stage::after {
- clear: both;
- content: ".";
- display: block;
- height: 0;
- line-height: 0;
- visibility: hidden;
-}
-
-.owl .owl-stage-outer {
- overflow: hidden;
- position: relative;
- transform: translate3d(0, 0, 0);
-}
-
-.owl .owl-item {
- backface-visibility: hidden;
- float: left;
- min-height: 1px;
- position: relative;
- -webkit-tap-highlight-color: transparent;
- -webkit-touch-callout: none;
- transform: translateZ(0);
-}
-
-.owl .owl-item > img {
- display: block;
- transform-style: preserve-3d;
- width: 100%;
-}
-
-.owl .owl-nav.disabled,
-.owl .owl-dots.disabled {
- display: none;
-}
-
-.owl .owl-prev,
-.owl .owl-next,
-.owl .owl-dot {
- cursor: pointer;
- user-select: none;
-}
-
-.owl .owl-prev,
-.owl .owl-next {
- align-items: center;
- background-color: var(--white-color);
- border: 1px solid var(--light-gray-color);
- border-radius: 3px;
- color: var(--dark-gray-color);
- display: flex;
- height: 30px;
- justify-content: center;
- outline: none;
- padding: 0;
- position: absolute;
- text-align: center;
- top: -86px;
- transition: color 0.5s var(--animation-base);
- width: 30px;
-}
-
-.owl .owl-prev.disabled,
-.owl .owl-next.disabled {
- color: var(--mid-gray-color);
- cursor: default;
-}
-
-.owl .owl-prev .icon,
-.owl .owl-next .icon {
- height: 18px;
- width: 18px;
-}
-
-.owl .owl-prev {
- right: 34px;
-}
-
-.owl .owl-next {
- right: 0;
-}
-
-.owl .owl-dots {
- display: flex;
- justify-content: center;
- margin-top: 20px;
-}
-
-.owl .owl-dot {
- align-items: center;
- border: 0;
- display: flex;
- height: 20px;
- justify-content: center;
- outline: none;
- padding: 0;
- width: 20px;
-}
-
-.owl .owl-dot span {
- background-color: var(--light-gray-color);
- border-radius: 50%;
- height: 8px;
- width: 8px;
-}
-
-.owl .owl-dot.active span {
- background-color: var(--black-color);
-}
-
-.owl.owl-loaded {
- display: block;
-}
-
-.owl.owl-loading {
- display: block;
- opacity: 0;
-}
-
-.owl.owl-hidden {
- opacity: 0;
-}
-
-.owl.owl-refresh .owl-item {
- visibility: hidden;
-}
-
-.owl.owl-drag .owl-item {
- user-select: none;
-}
-
-.owl.owl-grab {
- cursor: move;
-}
-
-.no-js .owl {
- display: block;
-}
diff --git a/assets/css/vendor/pswp.css b/assets/css/vendor/pswp.css
deleted file mode 100644
index 08801dfc..00000000
--- a/assets/css/vendor/pswp.css
+++ /dev/null
@@ -1,420 +0,0 @@
-.pswp {
- backface-visibility: hidden;
- display: none;
- height: 100%;
- left: 0;
- position: absolute;
- outline: none;
- overflow: hidden;
- top: 0;
- touch-action: none;
- width: 100%;
- z-index: 1500;
- -ms-touch-action: none;
- -webkit-text-size-adjust: 100%;
-}
-.pswp img {
- max-width: none;
-}
-.pswp--animate_opacity {
- opacity: 0.001;
- transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
- will-change: opacity;
-}
-.pswp--open {
- display: block;
-}
-.pswp--zoom-allowed .pswp__img {
- cursor: zoom-in;
-}
-.pswp--zoomed-in .pswp__img {
- cursor: grab;
-}
-.pswp--dragging .pswp__img {
- cursor: grabbing;
-}
-.pswp__bg {
- backface-visibility: hidden;
- background-color: rgba(0, 0, 0, 0.85);
- height: 100%;
- left: 0;
- opacity: 0;
- position: absolute;
- top: 0;
- transform: translateZ(0);
- transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
- width: 100%;
- will-change: opacity;
-}
-.pswp__scroll-wrap {
- height: 100%;
- left: 0;
- overflow: hidden;
- position: absolute;
- top: 0;
- width: 100%;
-}
-.pswp__container,
-.pswp__zoom-wrap {
- bottom: 0;
- left: 0;
- position: absolute;
- right: 0;
- top: 0;
- touch-action: none;
-}
-.pswp__container,
-.pswp__img {
- user-select: none;
- -webkit-tap-highlight-color: transparent;
- -webkit-touch-callout: none;
-}
-.pswp__zoom-wrap {
- position: absolute;
- transform-origin: left top;
- transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
- width: 100%;
-}
-.pswp--animated-in .pswp__bg,
-.pswp--animated-in .pswp__zoom-wrap {
- transition: none;
-}
-.pswp__container,
-.pswp__zoom-wrap {
- backface-visibility: hidden;
-}
-.pswp__item {
- bottom: 0;
- left: 0;
- overflow: hidden;
- position: absolute;
- right: 0;
- top: 0;
-}
-.pswp__img {
- height: auto;
- left: 0;
- position: absolute;
- top: 0;
- width: auto;
-}
-.pswp__img--placeholder {
- backface-visibility: hidden;
-}
-.pswp__img--placeholder--blank {
- background: var(--black-color);
-}
-.pswp--ie .pswp__img {
- height: auto !important;
- left: 0;
- top: 0;
- width: 100% !important;
-}
-.pswp__error-msg {
- color: var(--secondary-text-color);
- font-size: 14px;
- left: 0;
- line-height: 16px;
- margin-top: -8px;
- position: absolute;
- text-align: center;
- top: 50%;
- width: 100%;
-}
-.pswp__error-msg a {
- color: var(--secondary-text-color);
- text-decoration: underline;
-}
-.pswp__button {
- appearance: none;
- background: none;
- border: 0;
- box-shadow: none;
- cursor: pointer;
- display: block;
- float: right;
- height: 44px;
- margin: 0;
- overflow: visible;
- padding: 0;
- position: relative;
- transition: opacity 0.2s;
- width: 44px;
-}
-.pswp__button:focus,
-.pswp__button:hover {
- opacity: 1;
-}
-.pswp__button:active {
- opacity: 0.9;
- outline: none;
-}
-.pswp__button::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-.pswp__ui--over-close .pswp__button--close {
- opacity: 1;
-}
-.pswp__button,
-.pswp__button--arrow--left:before,
-.pswp__button--arrow--right:before {
- background: url(../images/default-skin.png) 0 0 no-repeat;
- background-size: 264px 88px;
- height: 44px;
- width: 44px;
-}
-@media (-webkit-min-device-pixel-ratio: 1.1), (-webkit-min-device-pixel-ratio: 1.09375), (min-resolution: 105dpi), (min-resolution: 1.1dppx) {
- .pswp--svg .pswp__button,
- .pswp--svg .pswp__button--arrow--left:before,
- .pswp--svg .pswp__button--arrow--right:before {
- background-image: url(../images/default-skin.svg);
- }
- .pswp--svg .pswp__button--arrow--left,
- .pswp--svg .pswp__button--arrow--right {
- background: none;
- }
-}
-.pswp__button--close {
- background-position: 0 -44px;
-}
-.pswp__button--share {
- background-position: -44px -44px;
-}
-.pswp__button--fs {
- display: none;
-}
-.pswp--supports-fs .pswp__button--fs {
- display: block;
-}
-.pswp--fs .pswp__button--fs {
- background-position: -44px 0;
-}
-.pswp__button--zoom {
- background-position: -88px 0;
- display: none;
-}
-.pswp--zoom-allowed .pswp__button--zoom {
- display: block;
-}
-.pswp--zoomed-in .pswp__button--zoom {
- background-position: -132px 0;
-}
-.pswp--touch .pswp__button--arrow--left,
-.pswp--touch .pswp__button--arrow--right {
- visibility: hidden;
-}
-.pswp__button--arrow--left,
-.pswp__button--arrow--right {
- background: none;
- height: 100px;
- margin-top: -50px;
- position: absolute;
- top: 50%;
- width: 70px;
-}
-.pswp__button--arrow--left {
- left: 0;
-}
-.pswp__button--arrow--right {
- right: 0;
-}
-.pswp__button--arrow--left:before,
-.pswp__button--arrow--right:before {
- content: "";
- height: 30px;
- position: absolute;
- top: 35px;
- width: 32px;
-}
-.pswp__button--arrow--left:before {
- background-position: -138px -44px;
- left: 6px;
-}
-.pswp__button--arrow--right:before {
- background-position: -94px -44px;
- right: 6px;
-}
-.pswp__counter {
- color: var(--white-color);
- font-size: 11px;
- font-weight: 700;
- height: 44px;
- left: 0;
- line-height: 44px;
- padding: 0 15px;
- position: absolute;
- top: 0;
- user-select: none;
-}
-.pswp__caption {
- bottom: 0;
- left: 0;
- min-height: 44px;
- position: absolute;
- width: 100%;
-}
-.pswp__caption__center {
- color: var(--white-color);
- font-size: 11px;
- line-height: 1.6;
- margin: 0 auto;
- max-width: 420px;
- padding: 25px 15px 30px;
- text-align: center;
-}
-.pswp__caption__center .post-caption-title {
- font-size: 15px;
- font-weight: 500;
- margin-bottom: 7px;
- text-transform: uppercase;
-}
-.pswp__caption__center .post-caption-meta-item + .post-caption-meta-item:before {
- content: "\02022";
- padding: 0 4px;
-}
-.pswp__caption--empty {
- display: none;
-}
-.pswp__caption--fake {
- visibility: hidden;
-}
-.pswp__preloader {
- direction: ltr;
- height: 44px;
- left: 50%;
- margin-left: -22px;
- opacity: 0;
- position: absolute;
- top: 0;
- transition: opacity 0.25s ease-out;
- width: 44px;
- will-change: opacity;
-}
-.pswp__preloader__icn {
- height: 20px;
- margin: 12px;
- width: 20px;
-}
-.pswp__preloader--active {
- opacity: 1;
-}
-.pswp__preloader--active .pswp__preloader__icn {
- background: url(../images/preloader.gif) 0 0 no-repeat;
-}
-.pswp--css_animation .pswp__preloader--active {
- opacity: 1;
-}
-.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn {
- animation: clockwise 500ms linear infinite;
-}
-.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut {
- animation: donut-rotate 1000ms cubic-bezier(0.4, 0, 0.22, 1) infinite;
-}
-.pswp--css_animation .pswp__preloader__icn {
- background: none;
- height: 14px;
- left: 15px;
- margin: 0;
- opacity: 0.75;
- position: absolute;
- top: 15px;
- width: 14px;
-}
-.pswp--css_animation .pswp__preloader__cut {
- height: 14px;
- overflow: hidden;
- position: relative;
- width: 7px;
-}
-.pswp--css_animation .pswp__preloader__donut {
- background: none;
- border: 2px solid var(--white-color);
- border-bottom-color: transparent;
- border-left-color: transparent;
- border-radius: 50%;
- box-sizing: border-box;
- height: 14px;
- left: 0;
- margin: 0;
- position: absolute;
- top: 0;
- width: 14px;
-}
-@media screen and (max-width: 1024px) {
- .pswp__preloader {
- float: right;
- left: auto;
- margin: 0;
- position: relative;
- top: auto;
- }
-}
-@keyframes clockwise {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-}
-@keyframes donut-rotate {
- 0% {
- transform: rotate(0);
- }
- 50% {
- transform: rotate(-140deg);
- }
- 100% {
- transform: rotate(0);
- }
-}
-.pswp__ui {
- opacity: 1;
- visibility: visible;
- z-index: 1550;
- -webkit-font-smoothing: auto;
-}
-.pswp__top-bar {
- height: 44px;
- left: 0;
- position: absolute;
- top: 0;
- width: 100%;
-}
-.pswp__caption,
-.pswp__top-bar,
-.pswp--has_mouse .pswp__button--arrow--left,
-.pswp--has_mouse .pswp__button--arrow--right {
- backface-visibility: hidden;
- transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
- will-change: opacity;
-}
-.pswp--has_mouse .pswp__button--arrow--left,
-.pswp--has_mouse .pswp__button--arrow--right {
- visibility: visible;
-}
-.pswp__ui--idle .pswp__top-bar {
- opacity: 0;
-}
-.pswp__ui--idle .pswp__button--arrow--left,
-.pswp__ui--idle .pswp__button--arrow--right {
- opacity: 0;
-}
-.pswp__ui--hidden .pswp__top-bar,
-.pswp__ui--hidden .pswp__caption,
-.pswp__ui--hidden .pswp__button--arrow--left,
-.pswp__ui--hidden .pswp__button--arrow--right {
- opacity: 0.001;
-}
-.pswp__ui--one-slide .pswp__button--arrow--left,
-.pswp__ui--one-slide .pswp__button--arrow--right,
-.pswp__ui--one-slide .pswp__counter {
- display: none;
-}
-.pswp__element--disabled {
- display: none !important;
-}
-.pswp--minimal--dark .pswp__top-bar {
- background: none;
-}
diff --git a/assets/images/footer-logo.png b/assets/images/footer-logo.png
new file mode 100644
index 00000000..b49629d6
Binary files /dev/null and b/assets/images/footer-logo.png differ
diff --git a/assets/images/home-impact.png b/assets/images/home-impact.png
new file mode 100644
index 00000000..7ee12bd4
Binary files /dev/null and b/assets/images/home-impact.png differ
diff --git a/assets/images/home-starter.png b/assets/images/home-starter.png
new file mode 100644
index 00000000..be89f68d
Binary files /dev/null and b/assets/images/home-starter.png differ
diff --git a/assets/js/lib/owl.carousel.js b/assets/js/lib/owl.carousel.js
deleted file mode 100644
index 66c67ebe..00000000
--- a/assets/js/lib/owl.carousel.js
+++ /dev/null
@@ -1,3448 +0,0 @@
-/**
- * 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 = [ $('