Commit 50e38c821c7e99b75ee7d496d74f747c879c8e6d

Authored by Administrator
1 parent 5842c37f

big commti

common/components/artboximage/ArtboxImageHelper.php
... ... @@ -21,6 +21,7 @@ class ArtboxImageHelper extends Object {
21 21 }
22 22  
23 23 public function getPreset($preset) {
  24 +
24 25 if (empty(self::$presets)) {
25 26 self::$presets = self::getDriver()->presets;
26 27 }
... ...
common/config/main.php
... ... @@ -98,8 +98,8 @@ return [
98 98 ],
99 99 'slider' => [
100 100 'resize' => [
101   - 'width' => 720,
102   - 'height' => 340,
  101 + 'width' => 1400,
  102 + 'height' => 600,
103 103 'master' => null
104 104 ],
105 105 ],
... ...
common/models/Slider.php
... ... @@ -65,4 +65,24 @@ class Slider extends \yii\db\ActiveRecord
65 65 {
66 66 return $this->hasMany(SliderImage::className(), ['slider_id' => 'slider_id'])->where([SliderImage::tableName().'.status'=>1]);
67 67 }
  68 +
  69 +
  70 + /**
  71 + * fetch stored image file name with complete path
  72 + * @return string
  73 + */
  74 + public function getImageFile()
  75 + {
  76 + return isset($this->image) ? '/storage/slider/' . $this->image : null;
  77 + }
  78 +
  79 + /**
  80 + * fetch stored image url
  81 + * @return string
  82 + */
  83 + public function getImageUrl()
  84 + {
  85 + // return a default image placeholder if your source image is not found
  86 + return isset($this->image) ? '/storage/slider/'. $this->image : '/storage/no_photo.png';
  87 + }
68 88 }
... ...
common/modules/product/widgets/views/products_block.php
... ... @@ -12,7 +12,7 @@ use yii\web\View;
12 12 -webkit-margin-start: 0px;
13 13 -webkit-margin-end: 0px;
14 14 font-weight: bold;"><?= $title?></span>
15   - <div class="owl-carousel">
  15 + <div id="<?=$class?>">
16 16 <?php foreach($products as $product) :?>
17 17 <?= $this->render('product_smart', ['product' => $product]);?>
18 18 <?php endforeach?>
... ... @@ -20,12 +20,12 @@ use yii\web\View;
20 20 <div class="both"></div>
21 21 </div>
22 22 </div>
23   - <?php $js = '$(".owl-carousel").owlCarousel({
  23 + <?php $js = "$('#$class').owlCarousel({
24 24 navigation:true,
25 25 navigationText: []
26 26 })
27 27  
28   -';
  28 +";
29 29 $this->registerJs($js, View::POS_READY);
30 30 ?>
31 31 <?php endif?>
32 32 \ No newline at end of file
... ...
frontend/controllers/SearchController.php 0 → 100755
  1 +<?php
  2 +
  3 +namespace frontend\controllers;
  4 +use frontend\models\ProductFrontendSearch;
  5 +use Yii;
  6 +use common\modules\product\models\Category;
  7 +use common\modules\product\models\Product;
  8 +use common\modules\product\models\ProductCategory;
  9 +use common\modules\product\models\ProductVariant;
  10 +use yii\web\HttpException;
  11 +
  12 +class SearchController extends \yii\web\Controller
  13 +{
  14 + public function actionIndex()
  15 + {
  16 +
  17 + $word = trim(Yii::$app->request->get('word', ''));
  18 +
  19 + if (!empty($word))
  20 + {
  21 +
  22 +
  23 + if( preg_match('/^\+?\d+$/', $word) && (iconv_strlen($word) > 4)){
  24 +
  25 + $params['keywords'][] = $word;
  26 +
  27 + $categoriesQuery = Category::find()
  28 + ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.category_id = '. Category::tableName() .'.category_id')
  29 + ->innerJoin(Product::tableName(), Product::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id')
  30 + ->innerJoin(ProductVariant::tableName(), ProductVariant::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id');
  31 + $categoriesQuery->andWhere(['ilike', 'product.name', $params['keywords'][0]]);
  32 + $categories = $categoriesQuery->all();
  33 +
  34 + } else {
  35 +
  36 + $params['keywords'] = explode(' ', preg_replace("|[\s,.!:&?~();-]|i", " ", $word));
  37 +
  38 + foreach($params['keywords'] as $i => &$keyword) {
  39 + $keyword = trim($keyword);
  40 + if (empty($keyword)) {
  41 + unset($params['keywords'][$i]);
  42 + }
  43 + }
  44 + array_unshift($params['keywords'], $word);
  45 +
  46 + $categoriesQuery = Category::find()
  47 + ->innerJoin(ProductCategory::tableName(), ProductCategory::tableName() .'.category_id = '. Category::tableName() .'.category_id')
  48 + ->innerJoin(Product::tableName(), Product::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id')
  49 + ->innerJoin(ProductVariant::tableName(), ProductVariant::tableName() .'.product_id = '. ProductCategory::tableName() .'.product_id');
  50 + foreach ($params['keywords'] as $keyword) {
  51 + $categoriesQuery->andWhere(['ilike', 'product.name', $keyword]);
  52 + }
  53 + $categoriesQuery->andWhere(['!=', ProductVariant::tableName() .'.stock', 0]);
  54 + $categories = $categoriesQuery->all();
  55 + }
  56 +
  57 + $productModel = new ProductFrontendSearch();
  58 + $productProvider = $productModel->search(null, $params);
  59 +
  60 +
  61 + return $this->render(
  62 + 'index',
  63 + [
  64 + 'keywords' => $params['keywords'],
  65 + 'productModel' => $productModel,
  66 + 'productProvider' => $productProvider,
  67 + 'categories' => $categories,
  68 + ]
  69 + );
  70 + }
  71 + else
  72 + {
  73 + throw new HttpException(404, 'Данной странице не существует!');
  74 + }
  75 + }
  76 +}
0 77 \ No newline at end of file
... ...
frontend/views/catalog/products.php
... ... @@ -229,22 +229,16 @@ use yii\helpers\Url;
229 229 <li class="view_table selected" onclick="return false;" title="таблица"><span></span></li>
230 230 <li class="view_mini_table" onclick="return false;" title="миниатюрная таблица"><span></span></li>
231 231 </ul>
232   - <ul class="ul sort_links">
233   - <li>Сортировка:</li>
234   -
235   - <li class="">
236   - <a href="#" onclick="window.location.href='http://www.linija-svitla.ua/lyustry-2.htm?ipp=36&sort=price&so=asc'; return false;">от дорогих</a><span class="arr"></span>
237   - </li>
238   - <li class="">
239   - <a href="#" onclick="window.location.href='http://www.linija-svitla.ua/lyustry-2.htm?ipp=36&sort=price&so=desc'; return false;">от дешевых</a><span class="arr"></span>
240   - </li>
241   - <li class="selected">
242   - <a href="#" onclick="window.location.href='http://www.linija-svitla.ua/lyustry-2.htm?'; return false;">по популярности</a><span class="arr"></span>
243   - </li>
244   - <li>
245   - <a href="#" onclick="return false;">новые поступления</a><span class="arr"></span>
246   - </li>
247   - </ul>
  232 + <div class="sort_block">
  233 + <span>Сортировка:</span>
  234 + <?= \yii\widgets\LinkSorter::widget([
  235 + 'sort' => $productProvider->sort,
  236 + 'attributes' => [
  237 + 'price',
  238 + ]
  239 + ]);
  240 + ?>
  241 + </div>
248 242 <div class="clearfix"></div>
249 243 </div>
250 244  
... ...
frontend/views/layouts/main.php
... ... @@ -150,17 +150,19 @@ AppAsset::register($this);
150 150 <div class="block-66">
151 151 <div id="header_search">
152 152 <!--<p><span class="popular_search_title">Популярные запросы</span> <a href="#">Led лампы</a>, <a href="#">Уличный фонарь</a></p>-->
153   - <form id="search_products" method="get" action="/search.htm">
  153 + <form id="search_products" method="get" action="/search">
154 154 <div class="input-group">
155 155 <div class="input-group-loop"></div>
156   - <input type="text" name="search_str" class="form-control" placeholder="введите артикул или ID" name="search" value="" required>
  156 + <input type="text" name="word" class="form-control" placeholder="введите артикул или ID" value="" required>
157 157 <span class="input-group-btn">
158   - <input class="btn btn-default" type="submit" name="send_search" value="Найти">
  158 + <input class="btn btn-default" type="submit" value="Найти">
159 159 <span class="search_btn_angle"></span>
160 160 </span>
161 161 </div><!-- /input-group -->
162 162 </form>
163 163 </div>
  164 +
  165 +
164 166 <div id="header_feedback">
165 167 <form>
166 168 <input type="text" name="phone" class="phone_short" placeholder="(0XX)XXX-XX-XX" />
... ...
frontend/views/modal/my_callback_modal_window.php
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +
  5 +?>
1 6 <div class="modal fade" id="myCallback" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
2 7 <div class="modal-dialog auth" role="document">
3 8 <div class="modal-content">
... ... @@ -13,17 +18,15 @@
13 18 <p>Оставьте номер вашего телефона и наш оператор перезвонит вам в течении часа.</p>
14 19 <div class="form-group">
15 20 <label for="СallbackName1">Ваше имя</label>
16   - <input type="text" class="form-control" id="СallbackName1" placeholder="">
  21 + <?= Html::textInput('name',"",['class'=>'consultation_name']) ?>
17 22 </div>
18 23  
19 24 <div class="form-group">
20 25 <label for="СallbackPhone1">Телефон</label>
21   - <input type="text" class="form-control" id="СallbackPhone1" placeholder="">
  26 + <?= Html::textInput('phone',"",['class'=>'consultation_phone']) ?>
22 27 </div>
23 28 <div class="example">примеры: +38 (044) 33-992-33 </div>
24   -
25   -
26   - <button type="submit" class="btn btn-default">Жду звонка</button>
  29 + <?= Html::submitButton("Жду звонка", ['class' => 'btn btn-default', 'name' => 'login-button']) ?>
27 30 <div class="clearfix"></div>
28 31 </form>
29 32 <br />
... ...
frontend/views/search/_product_search_item.php 0 → 100755
  1 +<?php
  2 + /**
  3 + * @var $model common\modules\product\models\Product
  4 + */
  5 +use yii\helpers\Html;
  6 +use yii\helpers\Url;
  7 +?>
  8 +<div class="catalog_item">
  9 + <div class="wrapper">
  10 + <div class="item_container" >
  11 + <input class="prodInfo" type="hidden" value="[]">
  12 + <div class="title">
  13 + <?= Html::a( $model->name, Url::to(['catalog/product', 'product' => $model->alias]), ['class'=>'btn-product-details'] )?>
  14 + </div>
  15 + <div class="img">
  16 + <a class="btn-product-details" href="<?= Url::to([
  17 + 'catalog/product',
  18 + 'product' => $model->alias
  19 + ]) ?>">
  20 + <?= \common\components\artboximage\ArtboxImageHelper::getImage($model->enabledVariants[ 0 ]->imageUrl, 'list', [
  21 + 'alt' => $model->category->name . ' ' . $model->fullname,
  22 + 'title' => $model->category->name . ' ' . $model->fullname,
  23 + 'class' => 'selected'
  24 + ]) ?>
  25 + </a>
  26 + <div class="info_icons">
  27 + <a href="#" class="btn buy_button" data-toggle="modal" data-target="#buyForm" data-id="<?=$model->variant->product_variant_id; ?>" lang="145">Купить</a>
  28 + <ul class="ul wishlike_block hidden">
  29 + <li class="compare hidden">
  30 + <a onclick="add2compare(); return false;" class="compare compare_text_link_3631483" href="#">К сравнению</a>
  31 + <span class="icon"></span>
  32 + </li>
  33 + <li class="like hidden">
  34 + <a class="like like_text_link_3631483" href="#">В избранное</a><span class="icon"></span>
  35 + </li>
  36 + </ul>
  37 + </div>
  38 + </div>
  39 + <div class="price">
  40 + <div class="dlexfduinxipi">
  41 + Цена:
  42 + <span class="main">
  43 + <?= $model->variant->price ?>
  44 + <span class="currency">грн</span>
  45 + </span>
  46 + </div>
  47 + </div>
  48 + <div class="additional_info params">
  49 + <div class="block_title">Особенности</div>
  50 + <div class="descr">
  51 + <div class="info">
  52 + <ul class="sv">
  53 +
  54 + <li><span>Бренд:</span> <?= $model->brand->name ?></li>
  55 +
  56 + <?php foreach($model->getActiveProperties($model->category->category_id) as $group): ?>
  57 + <li><span><?= $group->name ?> <?php foreach($group->_options as $option) : ?>&nbsp;</span><?= $option->ValueRenderHTML ?><?php endforeach ?></li>
  58 + <?php endforeach; ?>
  59 +
  60 +
  61 + </ul>
  62 + </div>
  63 + <div class="clearfix"></div>
  64 + </div>
  65 + <div class="price" style="display: none;">
  66 + <div class="dlexfduinxipi">
  67 + Цена:
  68 + <span class="main">
  69 + <?php
  70 +
  71 + echo '<div class="cost-block" itemprop="offers" itemscope itemtype="http://schema.org/Offer">';
  72 +
  73 + // есть скидка
  74 + echo '<p class="cost">';
  75 + if($model->enabledVariants[ 0 ]->price_old != 0 && $model->enabledVariants[ 0 ]->price_old != $model->enabledVariants[ 0 ]->price) {
  76 + echo '<strike><span id=\'old_cost\' itemprop="price">' . $model->enabledVariants[0]->price_old . '</span> грн.</strike>&nbsp;';
  77 + echo $model->enabledVariants[0]->price . ' <span>грн.</span></p>';
  78 + } else {
  79 + echo '<span itemprop="price">'.$model->enabledVariants[0]->price . ' </span><span>грн.</span></p>';
  80 + }
  81 + echo '<meta itemprop="priceCurrency" content = "UAH">';
  82 + echo '</div>';
  83 +
  84 + ?>
  85 + </span>
  86 + </div>
  87 + </div>
  88 + </div>
  89 + <div class="opacity_bg"></div>
  90 + </div>
  91 + </div>
  92 +</div>
0 93 \ No newline at end of file
... ...
frontend/views/search/index.php 0 → 100755
  1 +<?php
  2 +/**
  3 + * @var $productProvider \yii\data\ActiveDataProvider
  4 + * @var View $this
  5 + */
  6 +use frontend\widgets\FilterWidget;
  7 +use frontend\widgets\Seo;
  8 +use yii\helpers\Url;
  9 +use yii\web\View;
  10 +use yii\widgets\ListView;
  11 +$this->params['seo']['title'] = 'Поиск';
  12 +
  13 +$this->params['seo']['h1'] = 'Поиск';
  14 +
  15 +$this->params['breadcrumbs'][] = 'Поиск';
  16 +?>
  17 +<!-- Табы для слайдера -->
  18 +<div class="bigSlidertabs fixed" style="position:fixed;">
  19 + <div class="block-100">
  20 + <div class="tab1">
  21 + <a href="actionlist.htm">
  22 + <div class="tab_bg_1"></div>
  23 + <p>В данный момент у нас проходит <a href="actionlist.htm">25 акций</p></a>
  24 + </a>
  25 + </div>
  26 + <!--
  27 + <div class="tab2" style="display: none;">
  28 + <div class="tab_bg_2"></div>
  29 + <p>Поступило на продажу <a href="#">10 новинок</a></p>
  30 + </div>
  31 + -->
  32 + </div>
  33 +</div>
  34 +
  35 +<div class="container">
  36 + <div class="block-25" style="position: relative;">
  37 +
  38 + <div class="clearfix"></div>
  39 +
  40 +
  41 +
  42 +
  43 + <div class="columnLeftInfo">
  44 + <!-- del_columnLeftInfo -->
  45 +
  46 +
  47 +
  48 +
  49 +
  50 + <a href="http://ventolux.ua/"><img src="http://www.linija-svitla.ua/res/custom/images/banner/ventolux1.jpg"></a><br><br>
  51 +
  52 +
  53 + <table border="0" cellspacing="0" cellpadding="0" class="boxGen articleBox">
  54 + <tr class="bxhead">
  55 + <th class="bxhl"></th>
  56 + <th class="bxhc"><div class="h3">
  57 + <a href="view-articles/">Статьи</a>
  58 + </div></th>
  59 +
  60 + <th class="bxhr"></th>
  61 + </tr>
  62 +
  63 + <tr class="bxdelim">
  64 + <td></td>
  65 + <td></td>
  66 + <td></td>
  67 + </tr>
  68 + <tr class="bxmiddle">
  69 + <td class="bxl"></td>
  70 + <td class="bxc"> <div width="100%" class="articlesBox"><!-- cats_table-->
  71 + <div width="100%">
  72 + <div class="articleItem">
  73 + <span class="image">
  74 + </span>
  75 + <span align="left" class="title">
  76 + <a href="liniya-sveta-predstavila-trendovye-modeli-na-interior-mebel-85.htm" >
  77 + Линия света представила трендовые модели на Interior Mebel
  78 + </a>
  79 + </span>
  80 +
  81 + <div align="left" class="desc">
  82 + <p>В Киеве прошла выставка Interior Mebel, которая уже традиционно собирает лучшие образцы дизайна интерьера. На...
  83 + <a href="liniya-sveta-predstavila-trendovye-modeli-na-interior-mebel-85.htm" >
  84 + подробнее
  85 + </a>
  86 + </div>
  87 +
  88 + </div>
  89 +
  90 +
  91 + <div class="articleItem">
  92 + <span class="image">
  93 + </span>
  94 + <span align="left" class="title">
  95 + <a href="svetodiodnoe-osveschenie-light-topps-svetodiodnye-lampochki-lampy-colon-kupit-dlya-doma-ceny-v-ukraine-84.htm" >
  96 + Светодиодное освещение Light Topps | Светодиодные...
  97 + </a>
  98 + </span>
  99 +
  100 + <div align="left" class="desc">
  101 + О светодиодных лампах и светильниках, в которых используются светодиодные модули, написано немало и наверняка уже...
  102 + <a href="svetodiodnoe-osveschenie-light-topps-svetodiodnye-lampochki-lampy-colon-kupit-dlya-doma-ceny-v-ukraine-84.htm" >
  103 + подробнее
  104 + </a>
  105 + </div>
  106 +
  107 + </div>
  108 +
  109 +
  110 + <div class="articleItem">
  111 + <span class="image">
  112 + </span>
  113 + <span align="left" class="title">
  114 + <a href="lyustry-potolochnye-novye-vozmojnosti-upravleniya-svetom-82.htm" >
  115 + Люстры потолочные. Новые возможности управления светом
  116 + </a>
  117 + </span>
  118 +
  119 + <div align="left" class="desc">
  120 + Люстры потолочные оснащенные пультом дистанционного управления, позволяют включать/выключать, а также регулировать...
  121 + <a href="lyustry-potolochnye-novye-vozmojnosti-upravleniya-svetom-82.htm" >
  122 + подробнее
  123 + </a>
  124 + </div>
  125 +
  126 + </div>
  127 +
  128 +
  129 +
  130 +
  131 +
  132 +
  133 +
  134 +
  135 +
  136 +
  137 + <div style="clear: left;"></div>
  138 +
  139 +
  140 + </div>
  141 +
  142 +
  143 + </td>
  144 + <td class="bxr"></td>
  145 + </tr>
  146 + <tr class="bxbottom">
  147 + <td class="bxbl"></td>
  148 + <td class="bxbc"></td>
  149 + <td class="bxbr"></td>
  150 + </tr>
  151 + </table>
  152 +
  153 + <div class="clearfix"></div>
  154 +
  155 +
  156 + <!-- del_columnLeftInfo_end -->
  157 + </div>
  158 +
  159 +
  160 + <br />
  161 +
  162 +
  163 +
  164 + </div>
  165 + <div class="block-75" itemscope itemtype="http://schema.org/Product">
  166 +
  167 +
  168 +
  169 +
  170 + <script>
  171 +
  172 +
  173 + </script>
  174 +
  175 +
  176 +
  177 + <h1 class="title"><?= Seo::widget([ 'row'=>'h1'])?></h1>
  178 +
  179 +
  180 + <div class="list_filters_links">
  181 + <ul class="ul pagination">
  182 + <li>Товаров на странице:</li>
  183 + <select name="items_per_page" class="s" style="text-align:center;width:54px;" onChange="window.location='http://www.linija-svitla.ua/lyustry-2.htm?ipp='+this.value+'';" style="margin-right: -2px;">
  184 + <option label="9" value="9">9</option>
  185 + <option label="18" value="18">18</option>
  186 + <option label="36" value="36" selected="selected">36</option>
  187 + <option label="99" value="99">99</option>
  188 +
  189 + </select>
  190 + </ul>
  191 + <ul class="view_type">
  192 + <li class="view_text">Вид списка</li>
  193 + <li class="view_list" onclick="return false;" title="список"><span></span></li>
  194 + <li class="view_table selected" onclick="return false;" title="таблица"><span></span></li>
  195 + <li class="view_mini_table" onclick="return false;" title="миниатюрная таблица"><span></span></li>
  196 + </ul>
  197 + <ul class="ul sort_links">
  198 + <li>Сортировка:</li>
  199 +
  200 + <li class="">
  201 + <a href="#" onclick="window.location.href='http://www.linija-svitla.ua/lyustry-2.htm?ipp=36&sort=price&so=asc'; return false;">от дорогих</a><span class="arr"></span>
  202 + </li>
  203 + <li class="">
  204 + <a href="#" onclick="window.location.href='http://www.linija-svitla.ua/lyustry-2.htm?ipp=36&sort=price&so=desc'; return false;">от дешевых</a><span class="arr"></span>
  205 + </li>
  206 + <li class="selected">
  207 + <a href="#" onclick="window.location.href='http://www.linija-svitla.ua/lyustry-2.htm?'; return false;">по популярности</a><span class="arr"></span>
  208 + </li>
  209 + <li>
  210 + <a href="#" onclick="return false;">новые поступления</a><span class="arr"></span>
  211 + </li>
  212 + </ul>
  213 + <div class="clearfix"></div>
  214 + </div>
  215 +
  216 +
  217 +
  218 + <div class="clearfix"></div>
  219 +
  220 +
  221 +
  222 +
  223 +
  224 +
  225 +
  226 + <script language="JavaScript">
  227 + $(document).ready(function(){
  228 + $('.toolbar-list').click(function(event) {
  229 + //alert(1);
  230 + $('.toolbar-list').addClass('selected');
  231 + $('.toolbar-grid').removeClass('selected');
  232 + $('#centrit .prodBox').addClass('list');
  233 + JsHttpRequest.query(
  234 + 'hr_gate.php?test=500&r='+Math.random(),
  235 + {
  236 + 'sp': "prod_list_style"
  237 + ,'style': 1
  238 + },
  239 + function(result, errors) { },
  240 + true //disable caching
  241 + );
  242 + });
  243 + $('.toolbar-grid').click(function(event) {
  244 + $('.toolbar-grid').addClass('selected');
  245 + $('.toolbar-list').removeClass('selected');
  246 + $('#centrit .prodBox').removeClass('list');
  247 + JsHttpRequest.query(
  248 + 'hr_gate.php?test=500&r='+Math.random(),
  249 + {
  250 + 'sp': "prod_list_style"
  251 + ,'style': 2
  252 + },
  253 + function(result, errors) { },
  254 + true //disable caching
  255 + );
  256 +
  257 + });
  258 +
  259 + });
  260 + </script>
  261 +
  262 +
  263 +
  264 +
  265 + <div class="catalog_product_list view_table">
  266 +
  267 +
  268 + <?= ListView::widget([
  269 + 'dataProvider' => $productProvider,
  270 + 'itemView' => function ($model, $key, $index, $widget) {
  271 + return $this->render('_product_search_item',[
  272 + 'model' => $model
  273 + ]);
  274 + },
  275 + 'layout' => "{items}<div class=\"clearfix\"></div>{pager}",
  276 + ])
  277 +
  278 + ?>
  279 +
  280 +
  281 +
  282 +
  283 + <div class="clearfix"></div>
  284 + </div>
  285 +
  286 + <br>
  287 +
  288 +
  289 +
  290 +
  291 +
  292 +
  293 +
  294 + <div class="clearfix"></div>
  295 +
  296 +
  297 +
  298 +
  299 + <div class="clearfix"></div>
  300 +
  301 + <h2>Магазин люстр в Киеве: изделия на любой вкус!</h2>
  302 + <p>Любой интерьер будет смотреться незавершенным, если не выбраны подходящие люстры, светильники (Киев). Посетив салон люстр в Киеве можно подобрать действительно интересные осветительные приборы, внося новые черты в интерьер, расставляя правильные акценты, подчеркивая неповторимость дизайна. А благодаря нашему сайту «Линия света» вы сможете купить люстру в интернете, без труда подбирая подходящую модель и экономя свои средства.</p>
  303 + <h2>Приобрести люстры через интернет-магазин: что предлагается</h2>
  304 + <p>Если вы присматриваете, где можно купить люстру в Украине – заходите на наш сайт, у нас имеется огромный выбор разнообразной продукции. Через наш реализующий люстры в Киеве интернет-магазин можно подобрать любые модели – от популярной классики до ультрасовременных подвесов. При этом купить люстру в интернет-магазине представится возможность по весьма приятным расценкам. Если же вас интересует, как купить люстры, цены которых будут максимально невысокими – присмотритесь к предложениям в разделе «распродажа» на сайте. Вообще же наш демонстрирующий разнообразные люстры каталог (цены различные), включает такие типы продукции, как:</p>
  305 + <ul>
  306 + <li>Классические, подвесные. Продажа люстр этой разновидности ведется наиболее активно – они всегда в моде, хорошо смотрятся во всех интерьерах, отличаются практичностью. На такие люстры в Киеве цена может быть самой различной – но она всегда будет оптимальна качественности и внешней привлекательности присмотренного изделия.</li>
  307 + <li>Более креативные люстры – это разнообразные потолочные светильники. Эти качественные люстры и светильники могут иметь различные дизайны, быть разных размеров. Параметры такой люстры интернет-магазин может подобрать в соответствии с индивидуальными размерами помещения, его дизайном.</li>
  308 + </ul>
  309 + <p>Также вы всегда сможете заказать люстру в интернет-магазине «Linija-svitla» в том стиле, который наиболее подойдет под ваши требования. Наш магазин люстр может предложить изделия в винтажном стиле (достаточно модном сегодня), классические модели, а также ультрасовременные авангардные люстры и товары, относящиеся к стилю хай-тек. На все предлагаемые люстры цена в Украине – одна из наиболее доступных.</p>
  310 + <h2>Люстры он-лайн на сайте «Linija-svitla»: преимущества покупок</h2>
  311 + <p>Планируя купить люстру через интернет – оцените все преимущества сотрудничества с нашим сайтом:</p>
  312 + <ul>
  313 + <li>Наш каталог люстр включает большое количество разнообразных товаров. Поэтому с нами купить люстры в интернете можно быстро и без потери времени.</li>
  314 + <li>У нас можно качественные и красивые люстры купить от надежных производителей. Через наш ресурс, возможно купить люстру в Киеве от бренда Massive – изделия этого производителя красивы, добротно сделаны, отличаются стильным видом и долговечностью. Учитывайте, планируя купить люстру - цены на товары от Massive будут несколько выше, нежели на подделки, которые может предложить отечественный рынок, но эта стоимость оправдывается качественностью электроприборов (на которых, как известно, экономить нельзя).</li>
  315 + <li>Самая демократичная на такой предмет, как люстра, цена. Если вы решили купить люстру, магазин «Линия Света» всегда предоставит возможность приобрести действительно качественный товар по минимальным расценкам.</li>
  316 + </ul>
  317 + <h2>Где купить люстру в Киеве?</h2>
  318 + <p>Вопрос, «где можно купить люстры в Украине» решен – это можно сделать на сайте «Linija-svitla». Если вам требуется хорошие люстры купить - интернет-магазин в Украине «Линия света»  может предложить большой перечень интересных разновидностей товаров данной категории. Задаваясь вопросом «сколько стоит люстра» учитывайте, что осветительные приборы во многом будут отображать ваш статус. А это значит, что как приобретение, так и подключение люстры стоимость не может иметь слишком низкую. Выбирать следует в первую очередь качественную работу, а потом уже доступные расценки. И помочь найти нужный товар смогут наши магазины люстр в Киеве. Для тех же, кто предпочитает делать интернет-заказы существует доставка по городам всей Украины, таким как: Днепропетровск, Харьков, Одесса, Запорожье, Киев, Херсон, Мариуполь, Полтава, Кривой Рог, Винница, Сумы, Черкассы, Николаев, Кременчуг, Хмельницкий, Чернигов, Житомир и др. При этом, цена на все реализуемые  изделия вас наверняка сможет обрадовать.</p>
  319 +
  320 +
  321 + </div>
  322 +</div>
  323 +
  324 +<div class="container">
  325 + <p>
  326 + Люстры - одна из основных специализаций нашего каталога светильников в разделе люстры. Эти товары предоставлены у нас по самым лучшим ценам: Люстры Массив 41017/32/10, Люстры Массив 40851/33/10, Люстры Есео 40523/17/13, Люстры Массив 40865/11/10. Рекомендуем вам не сомневаться и позвонить нашему консультанту. Он поможет подобрать красивые люстры именно для вас. </p>
  327 +</div>
  328 +
  329 +
... ...
frontend/views/site/index.php
  1 +<?php
  2 + use frontend\widgets\Slider;
1 3  
2   -<script>
3   - $(document).ready(function() {
4   -
5   - $(window).load(function() {
6   -
7   - bottom = $('#bigSlider').position().top;
8   -
9   - //alert(currentScroll + " - " + bottom);
10   -
11   - currentScroll = $(window).scrollTop(); // get current position
12   -
13   - if (currentScroll > bottom) { // apply position: fixed if you
14   - $('.bigSlidertabs').addClass('fixed');
15   - $('.bigSlidertabs').css({ // scroll to that element or below it
16   - position: 'fixed'
17   - });
18   - } else { // apply position: static
19   - $('.bigSlidertabs').removeClass('fixed');
20   - $('.bigSlidertabs').css({ // if you scroll above it
21   - position: 'absolute'
22   - });
23   - }
24   -
25   - });
26   -
27   - $(window).scroll(function() { // assign scroll event listener
28   -
29   - bottom = $('#bigSlider').position().top;
30   -
31   - //alert(currentScroll + " - " + bottom);
32   -
33   - currentScroll = $(window).scrollTop(); // get current position
34   -
35   - if (currentScroll > bottom) { // apply position: fixed if you
36   - $('.bigSlidertabs').addClass('fixed');
37   - $('.bigSlidertabs').css({ // scroll to that element or below it
38   - position: 'fixed'
39   - });
40   - } else { // apply position: static
41   - $('.bigSlidertabs').removeClass('fixed');
42   - $('.bigSlidertabs').css({ // if you scroll above it
43   - position: 'absolute'
44   - });
45   - }
46   -
47   - });
48   -
49   - prev_img_url = $('#bigSlider #myCarousel').find('.item').last().find('img').attr('src');
50   - next_img_url = $('#bigSlider #myCarousel').find('.item').next().find('img').attr('src');
51   -
52   - $('#bigSlider #myCarousel').find('.img-nav.img-prev').attr('src',prev_img_url);
53   - $('#bigSlider #myCarousel').find('.img-nav.img-next').attr('src',next_img_url);
54   -
55   - $('#bigSlider #myCarousel').bind('slide.bs.carousel', function (e) {
56   - prev_img_url = $(this).find('.item.active').prev().find('img').attr('src');
57   - if(prev_img_url == undefined){
58   - prev_img_url = $('#bigSlider #myCarousel').find('.item').last().find('img').attr('src');
59   - }
60   -
61   - next_img_url = $(this).find('.item.active').next().find('img').attr('src');
62   - if(next_img_url == undefined){
63   - next_img_url = $('#bigSlider #myCarousel').find('.item').first().find('img').attr('src');
64   - }
65   -
66   - $(this).find('.img-nav.img-prev').attr('src',prev_img_url);
67   - $(this).find('.img-nav.img-next').attr('src',next_img_url);
68   - });
69   -
70   - });
71   -</script>
  4 +?>
72 5  
73 6  
74 7 <!---- SLIDER FOR Main page ------->
75   -<div id="bigSlider">
76   - <div id="myCarousel" class="carousel slide carousel-fade">
77   - <!-- Indicators -->
78   - <ol class="carousel-indicators">
79   - <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
80   - <li data-target="#myCarousel" data-slide-to="1"></li>
81   - <li data-target="#myCarousel" data-slide-to="2"></li>
82   - <li data-target="#myCarousel" data-slide-to="3"></li>
83   - <li data-target="#myCarousel" data-slide-to="4"></li>
84   - <li data-target="#myCarousel" data-slide-to="5"></li>
85   - </ol>
86   -
87   - <!-- Картинки в карусельке -->
88   - <div class="carousel-inner">
89   - <div class="active item">
90   - <a href="http://www.linija-svitla.ua/aktsiya.htm" title="При покупке светильника лампочка в подарок.*"> <img alt="При покупке светильника лампочка в подарок.*" src="http://www.linija-svitla.ua/res/custom/images/slider/lAMP FREE.jpg" />
91   - </a>
92   - </div>
93   - <div class="item">
94   - <a href="/detskie-15.htm" title="myKidsRoom"> <img alt="myKidsRoom" src="http://www.linija-svitla.ua/res/custom/images/slider/kids5w.jpg" />
95   - </a>
96   - </div>
97   - <div class="item">
98   - <a href="/sales.htm" title="Распродажа коллекций прошлых годов"> <img alt="Распродажа коллекций прошлых годов" src="http://www.linija-svitla.ua/res/custom/images/slider/Razprodaza.jpg" />
99   - </a>
100   - </div>
101   - <div class="item">
102   - <a href="http://www.linija-svitla.ua/light-topps-lt290209-8671.htm" title="iDual"> <img alt="iDual" src="http://www.linija-svitla.ua/res/custom/images/slider/iDual.jpg" />
103   - </a>
104   - </div>
105   - <div class="item">
106   - <img alt=" " src="http://www.linija-svitla.ua/res/custom/images/slider/3.jpg" />
107   -
108   - </div>
109   - <div class="item">
110   - <a href="/catalogues.htm" title="Модели"> <img alt="Модели" src="http://www.linija-svitla.ua/res/custom/images/slider/2.jpg" />
111   - </a>
112   - </div>
113   - </div>
114   - <!-- Навигационные элементы -->
115   - <a class="carousel-control left" href="#myCarousel" data-slide="prev">
116   - <span class="carousel-control-nav left"></span>
117   - <img class="img-nav img-prev" src="http://www.linija-svitla.ua/res/custom/images/slider/lAMP FREE.jpg" />
118   - </a>
119   - <a class="carousel-control right" href="#myCarousel" data-slide="next">
120   - <span class="carousel-control-nav right"></span>
121   - <img class="img-nav img-next" src="http://www.linija-svitla.ua/res/custom/images/slider/kids5w.jpg" />
122   - </a>
123   - </div>
124   - <!-- Табы для слайдера -->
125   - <div class="bigSlidertabs" >
126   - <div class="block-100">
127   - <div class="tab1">
128   - <a href="actionlist.htm">
129   - <div class="tab_bg_1"></div>
130   - <p>В данный момент у нас проходит <a href="actionlist.htm">25 акций</p></a>
131   - </a>
132   - </div>
133   -
134   - <div class="tab3">
135   - <a href="sales.htm">
136   - <div class="tab_bg_3"></div>
137   - <p>Вы можете значительно сэкономить при покупке. Посмотреть <a>все РАСПРОДАЖИ</a></p>
138   - </a>
139   - </div>
140   - </div>
141   - </div>
142   -
143   -
  8 +<div class="container">
  9 + <?= Slider::widget(["title"=>"HOME_SLIDER"]); ?>
144 10 </div>
145 11  
146 12  
... ...
frontend/web/css/css_header.css
... ... @@ -14,7 +14,16 @@
14 14 .option_image_block {
15 15 height: 110px;
16 16 }
17   -
  17 +.slider {
  18 + width: 100%;
  19 + height: 480px;
  20 + background: #eceff4;
  21 + margin-right: 25px;
  22 + display: inline-block;
  23 + float: left;
  24 + overflow: hidden;
  25 + margin-bottom: 35px;
  26 +}
18 27  
19 28 .owl-item .catalog_item{
20 29 float: none !important;
... ...
frontend/web/css/owl.carousel.css 0 → 100644
  1 +/*
  2 + * Owl Carousel - Animate Plugin
  3 + */
  4 +.owl-carousel .animated {
  5 + -webkit-animation-duration: 1000ms;
  6 + animation-duration: 1000ms;
  7 + -webkit-animation-fill-mode: both;
  8 + animation-fill-mode: both;
  9 +}
  10 +.owl-carousel .owl-animated-in {
  11 + z-index: 0;
  12 +}
  13 +.owl-carousel .owl-animated-out {
  14 + z-index: 1;
  15 +}
  16 +.owl-carousel .fadeOut {
  17 + -webkit-animation-name: fadeOut;
  18 + animation-name: fadeOut;
  19 +}
  20 +
  21 +@-webkit-keyframes fadeOut {
  22 + 0% {
  23 + opacity: 1;
  24 + }
  25 +
  26 + 100% {
  27 + opacity: 0;
  28 + }
  29 +}
  30 +@keyframes fadeOut {
  31 + 0% {
  32 + opacity: 1;
  33 + }
  34 +
  35 + 100% {
  36 + opacity: 0;
  37 + }
  38 +}
  39 +
  40 +/*
  41 + * Owl Carousel - Auto Height Plugin
  42 + */
  43 +.owl-height {
  44 + -webkit-transition: height 500ms ease-in-out;
  45 + -moz-transition: height 500ms ease-in-out;
  46 + -ms-transition: height 500ms ease-in-out;
  47 + -o-transition: height 500ms ease-in-out;
  48 + transition: height 500ms ease-in-out;
  49 +}
  50 +
  51 +/*
  52 + * Core Owl Carousel CSS File
  53 + */
  54 +.owl-carousel {
  55 + display: none;
  56 + width: 100%;
  57 + -webkit-tap-highlight-color: transparent;
  58 + /* position relative and z-index fix webkit rendering fonts issue */
  59 + position: relative;
  60 + z-index: 1;
  61 +}
  62 +.owl-carousel .owl-stage {
  63 + position: relative;
  64 + -ms-touch-action: pan-Y;
  65 +}
  66 +.owl-carousel .owl-stage:after {
  67 + content: ".";
  68 + display: block;
  69 + clear: both;
  70 + visibility: hidden;
  71 + line-height: 0;
  72 + height: 0;
  73 +}
  74 +.owl-carousel .owl-stage-outer {
  75 + position: relative;
  76 + overflow: hidden;
  77 + /* fix for flashing background */
  78 + -webkit-transform: translate3d(0px, 0px, 0px);
  79 +}
  80 +.owl-carousel .owl-controls .owl-nav .owl-prev,
  81 +.owl-carousel .owl-controls .owl-nav .owl-next,
  82 +.owl-carousel .owl-controls .owl-dot {
  83 + cursor: pointer;
  84 + cursor: hand;
  85 + -webkit-user-select: none;
  86 + -khtml-user-select: none;
  87 + -moz-user-select: none;
  88 + -ms-user-select: none;
  89 + user-select: none;
  90 +}
  91 +.owl-carousel.owl-loaded {
  92 + display: block;
  93 +}
  94 +.owl-carousel.owl-loading {
  95 + opacity: 0;
  96 + display: block;
  97 +}
  98 +.owl-carousel.owl-hidden {
  99 + opacity: 0;
  100 +}
  101 +.owl-carousel .owl-refresh .owl-item {
  102 + display: none;
  103 +}
  104 +.owl-carousel .owl-item {
  105 + position: relative;
  106 + min-height: 1px;
  107 + float: left;
  108 + -webkit-backface-visibility: hidden;
  109 + -webkit-tap-highlight-color: transparent;
  110 + -webkit-touch-callout: none;
  111 + -webkit-user-select: none;
  112 + -moz-user-select: none;
  113 + -ms-user-select: none;
  114 + user-select: none;
  115 +}
  116 +.owl-carousel .owl-item img {
  117 + display: block;
  118 + width: 100%;
  119 + -webkit-transform-style: preserve-3d;
  120 +}
  121 +.owl-carousel.owl-text-select-on .owl-item {
  122 + -webkit-user-select: auto;
  123 + -moz-user-select: auto;
  124 + -ms-user-select: auto;
  125 + user-select: auto;
  126 +}
  127 +.owl-carousel .owl-grab {
  128 + cursor: move;
  129 + cursor: -webkit-grab;
  130 + cursor: -o-grab;
  131 + cursor: -ms-grab;
  132 + cursor: grab;
  133 +}
  134 +.owl-carousel.owl-rtl {
  135 + direction: rtl;
  136 +}
  137 +.owl-carousel.owl-rtl .owl-item {
  138 + float: right;
  139 +}
  140 +
  141 +/* No Js */
  142 +.no-js .owl-carousel {
  143 + display: block;
  144 +}
  145 +
  146 +/*
  147 + * Owl Carousel - Lazy Load Plugin
  148 + */
  149 +.owl-carousel .owl-item .owl-lazy {
  150 + opacity: 0;
  151 + -webkit-transition: opacity 400ms ease;
  152 + -moz-transition: opacity 400ms ease;
  153 + -ms-transition: opacity 400ms ease;
  154 + -o-transition: opacity 400ms ease;
  155 + transition: opacity 400ms ease;
  156 +}
  157 +.owl-carousel .owl-item img {
  158 + transform-style: preserve-3d;
  159 +}
  160 +
  161 +/*
  162 + * Owl Carousel - Video Plugin
  163 + */
  164 +.owl-carousel .owl-video-wrapper {
  165 + position: relative;
  166 + height: 100%;
  167 + background: #000;
  168 +}
  169 +.owl-carousel .owl-video-play-icon {
  170 + position: absolute;
  171 + height: 80px;
  172 + width: 80px;
  173 + left: 50%;
  174 + top: 50%;
  175 + margin-left: -40px;
  176 + margin-top: -40px;
  177 + background: url("owl.video.play.png") no-repeat;
  178 + cursor: pointer;
  179 + z-index: 1;
  180 + -webkit-backface-visibility: hidden;
  181 + -webkit-transition: scale 100ms ease;
  182 + -moz-transition: scale 100ms ease;
  183 + -ms-transition: scale 100ms ease;
  184 + -o-transition: scale 100ms ease;
  185 + transition: scale 100ms ease;
  186 +}
  187 +.owl-carousel .owl-video-play-icon:hover {
  188 + -webkit-transition: scale(1.3, 1.3);
  189 + -moz-transition: scale(1.3, 1.3);
  190 + -ms-transition: scale(1.3, 1.3);
  191 + -o-transition: scale(1.3, 1.3);
  192 + transition: scale(1.3, 1.3);
  193 +}
  194 +.owl-carousel .owl-video-playing .owl-video-tn,
  195 +.owl-carousel .owl-video-playing .owl-video-play-icon {
  196 + display: none;
  197 +}
  198 +.owl-carousel .owl-video-tn {
  199 + opacity: 0;
  200 + height: 100%;
  201 + background-position: center center;
  202 + background-repeat: no-repeat;
  203 + -webkit-background-size: contain;
  204 + -moz-background-size: contain;
  205 + -o-background-size: contain;
  206 + background-size: contain;
  207 + -webkit-transition: opacity 400ms ease;
  208 + -moz-transition: opacity 400ms ease;
  209 + -ms-transition: opacity 400ms ease;
  210 + -o-transition: opacity 400ms ease;
  211 + transition: opacity 400ms ease;
  212 +}
  213 +.owl-carousel .owl-video-frame {
  214 + position: relative;
  215 + z-index: 1;
  216 +}
... ...
frontend/web/js/owl.carousel.js 0 → 100644
  1 +/**
  2 + * Owl carousel
  3 + * @version 2.0.0
  4 + * @author Bartosz Wojciechowski
  5 + * @license The MIT License (MIT)
  6 + * @todo Lazy Load Icon
  7 + * @todo prevent animationend bubling
  8 + * @todo itemsScaleUp
  9 + * @todo Test Zepto
  10 + * @todo stagePadding calculate wrong active classes
  11 + */
  12 +;(function($, window, document, undefined) {
  13 +
  14 + var drag, state, e;
  15 +
  16 + /**
  17 + * Template for status information about drag and touch events.
  18 + * @private
  19 + */
  20 + drag = {
  21 + start: 0,
  22 + startX: 0,
  23 + startY: 0,
  24 + current: 0,
  25 + currentX: 0,
  26 + currentY: 0,
  27 + offsetX: 0,
  28 + offsetY: 0,
  29 + distance: null,
  30 + startTime: 0,
  31 + endTime: 0,
  32 + updatedX: 0,
  33 + targetEl: null
  34 + };
  35 +
  36 + /**
  37 + * Template for some status informations.
  38 + * @private
  39 + */
  40 + state = {
  41 + isTouch: false,
  42 + isScrolling: false,
  43 + isSwiping: false,
  44 + direction: false,
  45 + inMotion: false
  46 + };
  47 +
  48 + /**
  49 + * Event functions references.
  50 + * @private
  51 + */
  52 + e = {
  53 + _onDragStart: null,
  54 + _onDragMove: null,
  55 + _onDragEnd: null,
  56 + _transitionEnd: null,
  57 + _resizer: null,
  58 + _responsiveCall: null,
  59 + _goToLoop: null,
  60 + _checkVisibile: null
  61 + };
  62 +
  63 + /**
  64 + * Creates a carousel.
  65 + * @class The Owl Carousel.
  66 + * @public
  67 + * @param {HTMLElement|jQuery} element - The element to create the carousel for.
  68 + * @param {Object} [options] - The options
  69 + */
  70 + function Owl(element, options) {
  71 +
  72 + /**
  73 + * Current settings for the carousel.
  74 + * @public
  75 + */
  76 + this.settings = null;
  77 +
  78 + /**
  79 + * Current options set by the caller including defaults.
  80 + * @public
  81 + */
  82 + this.options = $.extend({}, Owl.Defaults, options);
  83 +
  84 + /**
  85 + * Plugin element.
  86 + * @public
  87 + */
  88 + this.$element = $(element);
  89 +
  90 + /**
  91 + * Caches informations about drag and touch events.
  92 + */
  93 + this.drag = $.extend({}, drag);
  94 +
  95 + /**
  96 + * Caches some status informations.
  97 + * @protected
  98 + */
  99 + this.state = $.extend({}, state);
  100 +
  101 + /**
  102 + * @protected
  103 + * @todo Must be documented
  104 + */
  105 + this.e = $.extend({}, e);
  106 +
  107 + /**
  108 + * References to the running plugins of this carousel.
  109 + * @protected
  110 + */
  111 + this._plugins = {};
  112 +
  113 + /**
  114 + * Currently suppressed events to prevent them from beeing retriggered.
  115 + * @protected
  116 + */
  117 + this._supress = {};
  118 +
  119 + /**
  120 + * Absolute current position.
  121 + * @protected
  122 + */
  123 + this._current = null;
  124 +
  125 + /**
  126 + * Animation speed in milliseconds.
  127 + * @protected
  128 + */
  129 + this._speed = null;
  130 +
  131 + /**
  132 + * Coordinates of all items in pixel.
  133 + * @todo The name of this member is missleading.
  134 + * @protected
  135 + */
  136 + this._coordinates = [];
  137 +
  138 + /**
  139 + * Current breakpoint.
  140 + * @todo Real media queries would be nice.
  141 + * @protected
  142 + */
  143 + this._breakpoint = null;
  144 +
  145 + /**
  146 + * Current width of the plugin element.
  147 + */
  148 + this._width = null;
  149 +
  150 + /**
  151 + * All real items.
  152 + * @protected
  153 + */
  154 + this._items = [];
  155 +
  156 + /**
  157 + * All cloned items.
  158 + * @protected
  159 + */
  160 + this._clones = [];
  161 +
  162 + /**
  163 + * Merge values of all items.
  164 + * @todo Maybe this could be part of a plugin.
  165 + * @protected
  166 + */
  167 + this._mergers = [];
  168 +
  169 + /**
  170 + * Invalidated parts within the update process.
  171 + * @protected
  172 + */
  173 + this._invalidated = {};
  174 +
  175 + /**
  176 + * Ordered list of workers for the update process.
  177 + * @protected
  178 + */
  179 + this._pipe = [];
  180 +
  181 + $.each(Owl.Plugins, $.proxy(function(key, plugin) {
  182 + this._plugins[key[0].toLowerCase() + key.slice(1)]
  183 + = new plugin(this);
  184 + }, this));
  185 +
  186 + $.each(Owl.Pipe, $.proxy(function(priority, worker) {
  187 + this._pipe.push({
  188 + 'filter': worker.filter,
  189 + 'run': $.proxy(worker.run, this)
  190 + });
  191 + }, this));
  192 +
  193 + this.setup();
  194 + this.initialize();
  195 + }
  196 +
  197 + /**
  198 + * Default options for the carousel.
  199 + * @public
  200 + */
  201 + Owl.Defaults = {
  202 + items: 3,
  203 + loop: false,
  204 + center: false,
  205 +
  206 + mouseDrag: true,
  207 + touchDrag: true,
  208 + pullDrag: true,
  209 + freeDrag: false,
  210 +
  211 + margin: 0,
  212 + stagePadding: 0,
  213 +
  214 + merge: false,
  215 + mergeFit: true,
  216 + autoWidth: false,
  217 +
  218 + startPosition: 0,
  219 + rtl: false,
  220 +
  221 + smartSpeed: 250,
  222 + fluidSpeed: false,
  223 + dragEndSpeed: false,
  224 +
  225 + responsive: {},
  226 + responsiveRefreshRate: 200,
  227 + responsiveBaseElement: window,
  228 + responsiveClass: false,
  229 +
  230 + fallbackEasing: 'swing',
  231 +
  232 + info: false,
  233 +
  234 + nestedItemSelector: false,
  235 + itemElement: 'div',
  236 + stageElement: 'div',
  237 +
  238 + // Classes and Names
  239 + themeClass: 'owl-theme',
  240 + baseClass: 'owl-carousel',
  241 + itemClass: 'owl-item',
  242 + centerClass: 'center',
  243 + activeClass: 'active'
  244 + };
  245 +
  246 + /**
  247 + * Enumeration for width.
  248 + * @public
  249 + * @readonly
  250 + * @enum {String}
  251 + */
  252 + Owl.Width = {
  253 + Default: 'default',
  254 + Inner: 'inner',
  255 + Outer: 'outer'
  256 + };
  257 +
  258 + /**
  259 + * Contains all registered plugins.
  260 + * @public
  261 + */
  262 + Owl.Plugins = {};
  263 +
  264 + /**
  265 + * Update pipe.
  266 + */
  267 + Owl.Pipe = [ {
  268 + filter: [ 'width', 'items', 'settings' ],
  269 + run: function(cache) {
  270 + cache.current = this._items && this._items[this.relative(this._current)];
  271 + }
  272 + }, {
  273 + filter: [ 'items', 'settings' ],
  274 + run: function() {
  275 + var cached = this._clones,
  276 + clones = this.$stage.children('.cloned');
  277 +
  278 + if (clones.length !== cached.length || (!this.settings.loop && cached.length > 0)) {
  279 + this.$stage.children('.cloned').remove();
  280 + this._clones = [];
  281 + }
  282 + }
  283 + }, {
  284 + filter: [ 'items', 'settings' ],
  285 + run: function() {
  286 + var i, n,
  287 + clones = this._clones,
  288 + items = this._items,
  289 + delta = this.settings.loop ? clones.length - Math.max(this.settings.items * 2, 4) : 0;
  290 +
  291 + for (i = 0, n = Math.abs(delta / 2); i < n; i++) {
  292 + if (delta > 0) {
  293 + this.$stage.children().eq(items.length + clones.length - 1).remove();
  294 + clones.pop();
  295 + this.$stage.children().eq(0).remove();
  296 + clones.pop();
  297 + } else {
  298 + clones.push(clones.length / 2);
  299 + this.$stage.append(items[clones[clones.length - 1]].clone().addClass('cloned'));
  300 + clones.push(items.length - 1 - (clones.length - 1) / 2);
  301 + this.$stage.prepend(items[clones[clones.length - 1]].clone().addClass('cloned'));
  302 + }
  303 + }
  304 + }
  305 + }, {
  306 + filter: [ 'width', 'items', 'settings' ],
  307 + run: function() {
  308 + var rtl = (this.settings.rtl ? 1 : -1),
  309 + width = (this.width() / this.settings.items).toFixed(3),
  310 + coordinate = 0, merge, i, n;
  311 +
  312 + this._coordinates = [];
  313 + for (i = 0, n = this._clones.length + this._items.length; i < n; i++) {
  314 + merge = this._mergers[this.relative(i)];
  315 + merge = (this.settings.mergeFit && Math.min(merge, this.settings.items)) || merge;
  316 + coordinate += (this.settings.autoWidth ? this._items[this.relative(i)].width() + this.settings.margin : width * merge) * rtl;
  317 +
  318 + this._coordinates.push(coordinate);
  319 + }
  320 + }
  321 + }, {
  322 + filter: [ 'width', 'items', 'settings' ],
  323 + run: function() {
  324 + var i, n, width = (this.width() / this.settings.items).toFixed(3), css = {
  325 + 'width': Math.abs(this._coordinates[this._coordinates.length - 1]) + this.settings.stagePadding * 2,
  326 + 'padding-left': this.settings.stagePadding || '',
  327 + 'padding-right': this.settings.stagePadding || ''
  328 + };
  329 +
  330 + this.$stage.css(css);
  331 +
  332 + css = { 'width': this.settings.autoWidth ? 'auto' : width - this.settings.margin };
  333 + css[this.settings.rtl ? 'margin-left' : 'margin-right'] = this.settings.margin;
  334 +
  335 + if (!this.settings.autoWidth && $.grep(this._mergers, function(v) { return v > 1 }).length > 0) {
  336 + for (i = 0, n = this._coordinates.length; i < n; i++) {
  337 + css.width = Math.abs(this._coordinates[i]) - Math.abs(this._coordinates[i - 1] || 0) - this.settings.margin;
  338 + this.$stage.children().eq(i).css(css);
  339 + }
  340 + } else {
  341 + this.$stage.children().css(css);
  342 + }
  343 + }
  344 + }, {
  345 + filter: [ 'width', 'items', 'settings' ],
  346 + run: function(cache) {
  347 + cache.current && this.reset(this.$stage.children().index(cache.current));
  348 + }
  349 + }, {
  350 + filter: [ 'position' ],
  351 + run: function() {
  352 + this.animate(this.coordinates(this._current));
  353 + }
  354 + }, {
  355 + filter: [ 'width', 'position', 'items', 'settings' ],
  356 + run: function() {
  357 + var rtl = this.settings.rtl ? 1 : -1,
  358 + padding = this.settings.stagePadding * 2,
  359 + begin = this.coordinates(this.current()) + padding,
  360 + end = begin + this.width() * rtl,
  361 + inner, outer, matches = [], i, n;
  362 +
  363 + for (i = 0, n = this._coordinates.length; i < n; i++) {
  364 + inner = this._coordinates[i - 1] || 0;
  365 + outer = Math.abs(this._coordinates[i]) + padding * rtl;
  366 +
  367 + if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
  368 + || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
  369 + matches.push(i);
  370 + }
  371 + }
  372 +
  373 + this.$stage.children('.' + this.settings.activeClass).removeClass(this.settings.activeClass);
  374 + this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass(this.settings.activeClass);
  375 +
  376 + if (this.settings.center) {
  377 + this.$stage.children('.' + this.settings.centerClass).removeClass(this.settings.centerClass);
  378 + this.$stage.children().eq(this.current()).addClass(this.settings.centerClass);
  379 + }
  380 + }
  381 + } ];
  382 +
  383 + /**
  384 + * Initializes the carousel.
  385 + * @protected
  386 + */
  387 + Owl.prototype.initialize = function() {
  388 + this.trigger('initialize');
  389 +
  390 + this.$element
  391 + .addClass(this.settings.baseClass)
  392 + .addClass(this.settings.themeClass)
  393 + .toggleClass('owl-rtl', this.settings.rtl);
  394 +
  395 + // check support
  396 + this.browserSupport();
  397 +
  398 + if (this.settings.autoWidth && this.state.imagesLoaded !== true) {
  399 + var imgs, nestedSelector, width;
  400 + imgs = this.$element.find('img');
  401 + nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
  402 + width = this.$element.children(nestedSelector).width();
  403 +
  404 + if (imgs.length && width <= 0) {
  405 + this.preloadAutoWidthImages(imgs);
  406 + return false;
  407 + }
  408 + }
  409 +
  410 + this.$element.addClass('owl-loading');
  411 +
  412 + // create stage
  413 + this.$stage = $('<' + this.settings.stageElement + ' class="owl-stage"/>')
  414 + .wrap('<div class="owl-stage-outer">');
  415 +
  416 + // append stage
  417 + this.$element.append(this.$stage.parent());
  418 +
  419 + // append content
  420 + this.replace(this.$element.children().not(this.$stage.parent()));
  421 +
  422 + // set view width
  423 + this._width = this.$element.width();
  424 +
  425 + // update view
  426 + this.refresh();
  427 +
  428 + this.$element.removeClass('owl-loading').addClass('owl-loaded');
  429 +
  430 + // attach generic events
  431 + this.eventsCall();
  432 +
  433 + // attach generic events
  434 + this.internalEvents();
  435 +
  436 + // attach custom control events
  437 + this.addTriggerableEvents();
  438 +
  439 + this.trigger('initialized');
  440 + };
  441 +
  442 + /**
  443 + * Setups the current settings.
  444 + * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
  445 + * @todo Support for media queries by using `matchMedia` would be nice.
  446 + * @public
  447 + */
  448 + Owl.prototype.setup = function() {
  449 + var viewport = this.viewport(),
  450 + overwrites = this.options.responsive,
  451 + match = -1,
  452 + settings = null;
  453 +
  454 + if (!overwrites) {
  455 + settings = $.extend({}, this.options);
  456 + } else {
  457 + $.each(overwrites, function(breakpoint) {
  458 + if (breakpoint <= viewport && breakpoint > match) {
  459 + match = Number(breakpoint);
  460 + }
  461 + });
  462 +
  463 + settings = $.extend({}, this.options, overwrites[match]);
  464 + delete settings.responsive;
  465 +
  466 + // responsive class
  467 + if (settings.responsiveClass) {
  468 + this.$element.attr('class', function(i, c) {
  469 + return c.replace(/\b owl-responsive-\S+/g, '');
  470 + }).addClass('owl-responsive-' + match);
  471 + }
  472 + }
  473 +
  474 + if (this.settings === null || this._breakpoint !== match) {
  475 + this.trigger('change', { property: { name: 'settings', value: settings } });
  476 + this._breakpoint = match;
  477 + this.settings = settings;
  478 + this.invalidate('settings');
  479 + this.trigger('changed', { property: { name: 'settings', value: this.settings } });
  480 + }
  481 + };
  482 +
  483 + /**
  484 + * Updates option logic if necessery.
  485 + * @protected
  486 + */
  487 + Owl.prototype.optionsLogic = function() {
  488 + // Toggle Center class
  489 + this.$element.toggleClass('owl-center', this.settings.center);
  490 +
  491 + // if items number is less than in body
  492 + if (this.settings.loop && this._items.length < this.settings.items) {
  493 + this.settings.loop = false;
  494 + }
  495 +
  496 + if (this.settings.autoWidth) {
  497 + this.settings.stagePadding = false;
  498 + this.settings.merge = false;
  499 + }
  500 + };
  501 +
  502 + /**
  503 + * Prepares an item before add.
  504 + * @todo Rename event parameter `content` to `item`.
  505 + * @protected
  506 + * @returns {jQuery|HTMLElement} - The item container.
  507 + */
  508 + Owl.prototype.prepare = function(item) {
  509 + var event = this.trigger('prepare', { content: item });
  510 +
  511 + if (!event.data) {
  512 + event.data = $('<' + this.settings.itemElement + '/>')
  513 + .addClass(this.settings.itemClass).append(item)
  514 + }
  515 +
  516 + this.trigger('prepared', { content: event.data });
  517 +
  518 + return event.data;
  519 + };
  520 +
  521 + /**
  522 + * Updates the view.
  523 + * @public
  524 + */
  525 + Owl.prototype.update = function() {
  526 + var i = 0,
  527 + n = this._pipe.length,
  528 + filter = $.proxy(function(p) { return this[p] }, this._invalidated),
  529 + cache = {};
  530 +
  531 + while (i < n) {
  532 + if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
  533 + this._pipe[i].run(cache);
  534 + }
  535 + i++;
  536 + }
  537 +
  538 + this._invalidated = {};
  539 + };
  540 +
  541 + /**
  542 + * Gets the width of the view.
  543 + * @public
  544 + * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
  545 + * @returns {Number} - The width of the view in pixel.
  546 + */
  547 + Owl.prototype.width = function(dimension) {
  548 + dimension = dimension || Owl.Width.Default;
  549 + switch (dimension) {
  550 + case Owl.Width.Inner:
  551 + case Owl.Width.Outer:
  552 + return this._width;
  553 + default:
  554 + return this._width - this.settings.stagePadding * 2 + this.settings.margin;
  555 + }
  556 + };
  557 +
  558 + /**
  559 + * Refreshes the carousel primarily for adaptive purposes.
  560 + * @public
  561 + */
  562 + Owl.prototype.refresh = function() {
  563 + if (this._items.length === 0) {
  564 + return false;
  565 + }
  566 +
  567 + var start = new Date().getTime();
  568 +
  569 + this.trigger('refresh');
  570 +
  571 + this.setup();
  572 +
  573 + this.optionsLogic();
  574 +
  575 + // hide and show methods helps here to set a proper widths,
  576 + // this prevents scrollbar to be calculated in stage width
  577 + this.$stage.addClass('owl-refresh');
  578 +
  579 + this.update();
  580 +
  581 + this.$stage.removeClass('owl-refresh');
  582 +
  583 + this.state.orientation = window.orientation;
  584 +
  585 + this.watchVisibility();
  586 +
  587 + this.trigger('refreshed');
  588 + };
  589 +
  590 + /**
  591 + * Save internal event references and add event based functions.
  592 + * @protected
  593 + */
  594 + Owl.prototype.eventsCall = function() {
  595 + // Save events references
  596 + this.e._onDragStart = $.proxy(function(e) {
  597 + this.onDragStart(e);
  598 + }, this);
  599 + this.e._onDragMove = $.proxy(function(e) {
  600 + this.onDragMove(e);
  601 + }, this);
  602 + this.e._onDragEnd = $.proxy(function(e) {
  603 + this.onDragEnd(e);
  604 + }, this);
  605 + this.e._onResize = $.proxy(function(e) {
  606 + this.onResize(e);
  607 + }, this);
  608 + this.e._transitionEnd = $.proxy(function(e) {
  609 + this.transitionEnd(e);
  610 + }, this);
  611 + this.e._preventClick = $.proxy(function(e) {
  612 + this.preventClick(e);
  613 + }, this);
  614 + };
  615 +
  616 + /**
  617 + * Checks window `resize` event.
  618 + * @protected
  619 + */
  620 + Owl.prototype.onThrottledResize = function() {
  621 + window.clearTimeout(this.resizeTimer);
  622 + this.resizeTimer = window.setTimeout(this.e._onResize, this.settings.responsiveRefreshRate);
  623 + };
  624 +
  625 + /**
  626 + * Checks window `resize` event.
  627 + * @protected
  628 + */
  629 + Owl.prototype.onResize = function() {
  630 + if (!this._items.length) {
  631 + return false;
  632 + }
  633 +
  634 + if (this._width === this.$element.width()) {
  635 + return false;
  636 + }
  637 +
  638 + if (this.trigger('resize').isDefaultPrevented()) {
  639 + return false;
  640 + }
  641 +
  642 + this._width = this.$element.width();
  643 +
  644 + this.invalidate('width');
  645 +
  646 + this.refresh();
  647 +
  648 + this.trigger('resized');
  649 + };
  650 +
  651 + /**
  652 + * Checks for touch/mouse drag event type and add run event handlers.
  653 + * @protected
  654 + */
  655 + Owl.prototype.eventsRouter = function(event) {
  656 + var type = event.type;
  657 +
  658 + if (type === "mousedown" || type === "touchstart") {
  659 + this.onDragStart(event);
  660 + } else if (type === "mousemove" || type === "touchmove") {
  661 + this.onDragMove(event);
  662 + } else if (type === "mouseup" || type === "touchend") {
  663 + this.onDragEnd(event);
  664 + } else if (type === "touchcancel") {
  665 + this.onDragEnd(event);
  666 + }
  667 + };
  668 +
  669 + /**
  670 + * Checks for touch/mouse drag options and add necessery event handlers.
  671 + * @protected
  672 + */
  673 + Owl.prototype.internalEvents = function() {
  674 + var isTouch = isTouchSupport(),
  675 + isTouchIE = isTouchSupportIE();
  676 +
  677 + if (this.settings.mouseDrag){
  678 + this.$stage.on('mousedown', $.proxy(function(event) { this.eventsRouter(event) }, this));
  679 + this.$stage.on('dragstart', function() { return false });
  680 + this.$stage.get(0).onselectstart = function() { return false };
  681 + } else {
  682 + this.$element.addClass('owl-text-select-on');
  683 + }
  684 +
  685 + if (this.settings.touchDrag && !isTouchIE){
  686 + this.$stage.on('touchstart touchcancel', $.proxy(function(event) { this.eventsRouter(event) }, this));
  687 + }
  688 +
  689 + // catch transitionEnd event
  690 + if (this.transitionEndVendor) {
  691 + this.on(this.$stage.get(0), this.transitionEndVendor, this.e._transitionEnd, false);
  692 + }
  693 +
  694 + // responsive
  695 + if (this.settings.responsive !== false) {
  696 + this.on(window, 'resize', $.proxy(this.onThrottledResize, this));
  697 + }
  698 + };
  699 +
  700 + /**
  701 + * Handles touchstart/mousedown event.
  702 + * @protected
  703 + * @param {Event} event - The event arguments.
  704 + */
  705 + Owl.prototype.onDragStart = function(event) {
  706 + var ev, isTouchEvent, pageX, pageY, animatedPos;
  707 +
  708 + ev = event.originalEvent || event || window.event;
  709 +
  710 + // prevent right click
  711 + if (ev.which === 3 || this.state.isTouch) {
  712 + return false;
  713 + }
  714 +
  715 + if (ev.type === 'mousedown') {
  716 + this.$stage.addClass('owl-grab');
  717 + }
  718 +
  719 + this.trigger('drag');
  720 + this.drag.startTime = new Date().getTime();
  721 + this.speed(0);
  722 + this.state.isTouch = true;
  723 + this.state.isScrolling = false;
  724 + this.state.isSwiping = false;
  725 + this.drag.distance = 0;
  726 +
  727 + pageX = getTouches(ev).x;
  728 + pageY = getTouches(ev).y;
  729 +
  730 + // get stage position left
  731 + this.drag.offsetX = this.$stage.position().left;
  732 + this.drag.offsetY = this.$stage.position().top;
  733 +
  734 + if (this.settings.rtl) {
  735 + this.drag.offsetX = this.$stage.position().left + this.$stage.width() - this.width()
  736 + + this.settings.margin;
  737 + }
  738 +
  739 + // catch position // ie to fix
  740 + if (this.state.inMotion && this.support3d) {
  741 + animatedPos = this.getTransformProperty();
  742 + this.drag.offsetX = animatedPos;
  743 + this.animate(animatedPos);
  744 + this.state.inMotion = true;
  745 + } else if (this.state.inMotion && !this.support3d) {
  746 + this.state.inMotion = false;
  747 + return false;
  748 + }
  749 +
  750 + this.drag.startX = pageX - this.drag.offsetX;
  751 + this.drag.startY = pageY - this.drag.offsetY;
  752 +
  753 + this.drag.start = pageX - this.drag.startX;
  754 + this.drag.targetEl = ev.target || ev.srcElement;
  755 + this.drag.updatedX = this.drag.start;
  756 +
  757 + // to do/check
  758 + // prevent links and images dragging;
  759 + if (this.drag.targetEl.tagName === "IMG" || this.drag.targetEl.tagName === "A") {
  760 + this.drag.targetEl.draggable = false;
  761 + }
  762 +
  763 + $(document).on('mousemove.owl.dragEvents mouseup.owl.dragEvents touchmove.owl.dragEvents touchend.owl.dragEvents', $.proxy(function(event) {this.eventsRouter(event)},this));
  764 + };
  765 +
  766 + /**
  767 + * Handles the touchmove/mousemove events.
  768 + * @todo Simplify
  769 + * @protected
  770 + * @param {Event} event - The event arguments.
  771 + */
  772 + Owl.prototype.onDragMove = function(event) {
  773 + var ev, isTouchEvent, pageX, pageY, minValue, maxValue, pull;
  774 +
  775 + if (!this.state.isTouch) {
  776 + return;
  777 + }
  778 +
  779 + if (this.state.isScrolling) {
  780 + return;
  781 + }
  782 +
  783 + ev = event.originalEvent || event || window.event;
  784 +
  785 + pageX = getTouches(ev).x;
  786 + pageY = getTouches(ev).y;
  787 +
  788 + // Drag Direction
  789 + this.drag.currentX = pageX - this.drag.startX;
  790 + this.drag.currentY = pageY - this.drag.startY;
  791 + this.drag.distance = this.drag.currentX - this.drag.offsetX;
  792 +
  793 + // Check move direction
  794 + if (this.drag.distance < 0) {
  795 + this.state.direction = this.settings.rtl ? 'right' : 'left';
  796 + } else if (this.drag.distance > 0) {
  797 + this.state.direction = this.settings.rtl ? 'left' : 'right';
  798 + }
  799 + // Loop
  800 + if (this.settings.loop) {
  801 + if (this.op(this.drag.currentX, '>', this.coordinates(this.minimum())) && this.state.direction === 'right') {
  802 + this.drag.currentX -= (this.settings.center && this.coordinates(0)) - this.coordinates(this._items.length);
  803 + } else if (this.op(this.drag.currentX, '<', this.coordinates(this.maximum())) && this.state.direction === 'left') {
  804 + this.drag.currentX += (this.settings.center && this.coordinates(0)) - this.coordinates(this._items.length);
  805 + }
  806 + } else {
  807 + // pull
  808 + minValue = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
  809 + maxValue = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
  810 + pull = this.settings.pullDrag ? this.drag.distance / 5 : 0;
  811 + this.drag.currentX = Math.max(Math.min(this.drag.currentX, minValue + pull), maxValue + pull);
  812 + }
  813 +
  814 + // Lock browser if swiping horizontal
  815 +
  816 + if ((this.drag.distance > 8 || this.drag.distance < -8)) {
  817 + if (ev.preventDefault !== undefined) {
  818 + ev.preventDefault();
  819 + } else {
  820 + ev.returnValue = false;
  821 + }
  822 + this.state.isSwiping = true;
  823 + }
  824 +
  825 + this.drag.updatedX = this.drag.currentX;
  826 +
  827 + // Lock Owl if scrolling
  828 + if ((this.drag.currentY > 16 || this.drag.currentY < -16) && this.state.isSwiping === false) {
  829 + this.state.isScrolling = true;
  830 + this.drag.updatedX = this.drag.start;
  831 + }
  832 +
  833 + this.animate(this.drag.updatedX);
  834 + };
  835 +
  836 + /**
  837 + * Handles the touchend/mouseup events.
  838 + * @protected
  839 + */
  840 + Owl.prototype.onDragEnd = function(event) {
  841 + var compareTimes, distanceAbs, closest;
  842 +
  843 + if (!this.state.isTouch) {
  844 + return;
  845 + }
  846 +
  847 + if (event.type === 'mouseup') {
  848 + this.$stage.removeClass('owl-grab');
  849 + }
  850 +
  851 + this.trigger('dragged');
  852 +
  853 + // prevent links and images dragging;
  854 + this.drag.targetEl.removeAttribute("draggable");
  855 +
  856 + // remove drag event listeners
  857 +
  858 + this.state.isTouch = false;
  859 + this.state.isScrolling = false;
  860 + this.state.isSwiping = false;
  861 +
  862 + // to check
  863 + if (this.drag.distance === 0 && this.state.inMotion !== true) {
  864 + this.state.inMotion = false;
  865 + return false;
  866 + }
  867 +
  868 + // prevent clicks while scrolling
  869 +
  870 + this.drag.endTime = new Date().getTime();
  871 + compareTimes = this.drag.endTime - this.drag.startTime;
  872 + distanceAbs = Math.abs(this.drag.distance);
  873 +
  874 + // to test
  875 + if (distanceAbs > 3 || compareTimes > 300) {
  876 + this.removeClick(this.drag.targetEl);
  877 + }
  878 +
  879 + closest = this.closest(this.drag.updatedX);
  880 +
  881 + this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
  882 + this.current(closest);
  883 + this.invalidate('position');
  884 + this.update();
  885 +
  886 + // if pullDrag is off then fire transitionEnd event manually when stick
  887 + // to border
  888 + if (!this.settings.pullDrag && this.drag.updatedX === this.coordinates(closest)) {
  889 + this.transitionEnd();
  890 + }
  891 +
  892 + this.drag.distance = 0;
  893 +
  894 + $(document).off('.owl.dragEvents');
  895 + };
  896 +
  897 + /**
  898 + * Attaches `preventClick` to disable link while swipping.
  899 + * @protected
  900 + * @param {HTMLElement} [target] - The target of the `click` event.
  901 + */
  902 + Owl.prototype.removeClick = function(target) {
  903 + this.drag.targetEl = target;
  904 + $(target).on('click.preventClick', this.e._preventClick);
  905 + // to make sure click is removed:
  906 + window.setTimeout(function() {
  907 + $(target).off('click.preventClick');
  908 + }, 300);
  909 + };
  910 +
  911 + /**
  912 + * Suppresses click event.
  913 + * @protected
  914 + * @param {Event} ev - The event arguments.
  915 + */
  916 + Owl.prototype.preventClick = function(ev) {
  917 + if (ev.preventDefault) {
  918 + ev.preventDefault();
  919 + } else {
  920 + ev.returnValue = false;
  921 + }
  922 + if (ev.stopPropagation) {
  923 + ev.stopPropagation();
  924 + }
  925 + $(ev.target).off('click.preventClick');
  926 + };
  927 +
  928 + /**
  929 + * Catches stage position while animate (only CSS3).
  930 + * @protected
  931 + * @returns
  932 + */
  933 + Owl.prototype.getTransformProperty = function() {
  934 + var transform, matrix3d;
  935 +
  936 + transform = window.getComputedStyle(this.$stage.get(0), null).getPropertyValue(this.vendorName + 'transform');
  937 + // var transform = this.$stage.css(this.vendorName + 'transform')
  938 + transform = transform.replace(/matrix(3d)?\(|\)/g, '').split(',');
  939 + matrix3d = transform.length === 16;
  940 +
  941 + return matrix3d !== true ? transform[4] : transform[12];
  942 + };
  943 +
  944 + /**
  945 + * Gets absolute position of the closest item for a coordinate.
  946 + * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
  947 + * @protected
  948 + * @param {Number} coordinate - The coordinate in pixel.
  949 + * @return {Number} - The absolute position of the closest item.
  950 + */
  951 + Owl.prototype.closest = function(coordinate) {
  952 + var position = -1, pull = 30, width = this.width(), coordinates = this.coordinates();
  953 +
  954 + if (!this.settings.freeDrag) {
  955 + // check closest item
  956 + $.each(coordinates, $.proxy(function(index, value) {
  957 + if (coordinate > value - pull && coordinate < value + pull) {
  958 + position = index;
  959 + } else if (this.op(coordinate, '<', value)
  960 + && this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
  961 + position = this.state.direction === 'left' ? index + 1 : index;
  962 + }
  963 + return position === -1;
  964 + }, this));
  965 + }
  966 +
  967 + if (!this.settings.loop) {
  968 + // non loop boundries
  969 + if (this.op(coordinate, '>', coordinates[this.minimum()])) {
  970 + position = coordinate = this.minimum();
  971 + } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
  972 + position = coordinate = this.maximum();
  973 + }
  974 + }
  975 +
  976 + return position;
  977 + };
  978 +
  979 + /**
  980 + * Animates the stage.
  981 + * @public
  982 + * @param {Number} coordinate - The coordinate in pixels.
  983 + */
  984 + Owl.prototype.animate = function(coordinate) {
  985 + this.trigger('translate');
  986 + this.state.inMotion = this.speed() > 0;
  987 +
  988 + if (this.support3d) {
  989 + this.$stage.css({
  990 + transform: 'translate3d(' + coordinate + 'px' + ',0px, 0px)',
  991 + transition: (this.speed() / 1000) + 's'
  992 + });
  993 + } else if (this.state.isTouch) {
  994 + this.$stage.css({
  995 + left: coordinate + 'px'
  996 + });
  997 + } else {
  998 + this.$stage.animate({
  999 + left: coordinate
  1000 + }, this.speed() / 1000, this.settings.fallbackEasing, $.proxy(function() {
  1001 + if (this.state.inMotion) {
  1002 + this.transitionEnd();
  1003 + }
  1004 + }, this));
  1005 + }
  1006 + };
  1007 +
  1008 + /**
  1009 + * Sets the absolute position of the current item.
  1010 + * @public
  1011 + * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
  1012 + * @returns {Number} - The absolute position of the current item.
  1013 + */
  1014 + Owl.prototype.current = function(position) {
  1015 + if (position === undefined) {
  1016 + return this._current;
  1017 + }
  1018 +
  1019 + if (this._items.length === 0) {
  1020 + return undefined;
  1021 + }
  1022 +
  1023 + position = this.normalize(position);
  1024 +
  1025 + if (this._current !== position) {
  1026 + var event = this.trigger('change', { property: { name: 'position', value: position } });
  1027 +
  1028 + if (event.data !== undefined) {
  1029 + position = this.normalize(event.data);
  1030 + }
  1031 +
  1032 + this._current = position;
  1033 +
  1034 + this.invalidate('position');
  1035 +
  1036 + this.trigger('changed', { property: { name: 'position', value: this._current } });
  1037 + }
  1038 +
  1039 + return this._current;
  1040 + };
  1041 +
  1042 + /**
  1043 + * Invalidates the given part of the update routine.
  1044 + * @param {String} part - The part to invalidate.
  1045 + */
  1046 + Owl.prototype.invalidate = function(part) {
  1047 + this._invalidated[part] = true;
  1048 + }
  1049 +
  1050 + /**
  1051 + * Resets the absolute position of the current item.
  1052 + * @public
  1053 + * @param {Number} position - The absolute position of the new item.
  1054 + */
  1055 + Owl.prototype.reset = function(position) {
  1056 + position = this.normalize(position);
  1057 +
  1058 + if (position === undefined) {
  1059 + return;
  1060 + }
  1061 +
  1062 + this._speed = 0;
  1063 + this._current = position;
  1064 +
  1065 + this.suppress([ 'translate', 'translated' ]);
  1066 +
  1067 + this.animate(this.coordinates(position));
  1068 +
  1069 + this.release([ 'translate', 'translated' ]);
  1070 + };
  1071 +
  1072 + /**
  1073 + * Normalizes an absolute or a relative position for an item.
  1074 + * @public
  1075 + * @param {Number} position - The absolute or relative position to normalize.
  1076 + * @param {Boolean} [relative=false] - Whether the given position is relative or not.
  1077 + * @returns {Number} - The normalized position.
  1078 + */
  1079 + Owl.prototype.normalize = function(position, relative) {
  1080 + var n = (relative ? this._items.length : this._items.length + this._clones.length);
  1081 +
  1082 + if (!$.isNumeric(position) || n < 1) {
  1083 + return undefined;
  1084 + }
  1085 +
  1086 + if (this._clones.length) {
  1087 + position = ((position % n) + n) % n;
  1088 + } else {
  1089 + position = Math.max(this.minimum(relative), Math.min(this.maximum(relative), position));
  1090 + }
  1091 +
  1092 + return position;
  1093 + };
  1094 +
  1095 + /**
  1096 + * Converts an absolute position for an item into a relative position.
  1097 + * @public
  1098 + * @param {Number} position - The absolute position to convert.
  1099 + * @returns {Number} - The converted position.
  1100 + */
  1101 + Owl.prototype.relative = function(position) {
  1102 + position = this.normalize(position);
  1103 + position = position - this._clones.length / 2;
  1104 + return this.normalize(position, true);
  1105 + };
  1106 +
  1107 + /**
  1108 + * Gets the maximum position for an item.
  1109 + * @public
  1110 + * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
  1111 + * @returns {Number}
  1112 + */
  1113 + Owl.prototype.maximum = function(relative) {
  1114 + var maximum, width, i = 0, coordinate,
  1115 + settings = this.settings;
  1116 +
  1117 + if (relative) {
  1118 + return this._items.length - 1;
  1119 + }
  1120 +
  1121 + if (!settings.loop && settings.center) {
  1122 + maximum = this._items.length - 1;
  1123 + } else if (!settings.loop && !settings.center) {
  1124 + maximum = this._items.length - settings.items;
  1125 + } else if (settings.loop || settings.center) {
  1126 + maximum = this._items.length + settings.items;
  1127 + } else if (settings.autoWidth || settings.merge) {
  1128 + revert = settings.rtl ? 1 : -1;
  1129 + width = this.$stage.width() - this.$element.width();
  1130 + while (coordinate = this.coordinates(i)) {
  1131 + if (coordinate * revert >= width) {
  1132 + break;
  1133 + }
  1134 + maximum = ++i;
  1135 + }
  1136 + } else {
  1137 + throw 'Can not detect maximum absolute position.'
  1138 + }
  1139 +
  1140 + return maximum;
  1141 + };
  1142 +
  1143 + /**
  1144 + * Gets the minimum position for an item.
  1145 + * @public
  1146 + * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
  1147 + * @returns {Number}
  1148 + */
  1149 + Owl.prototype.minimum = function(relative) {
  1150 + if (relative) {
  1151 + return 0;
  1152 + }
  1153 +
  1154 + return this._clones.length / 2;
  1155 + };
  1156 +
  1157 + /**
  1158 + * Gets an item at the specified relative position.
  1159 + * @public
  1160 + * @param {Number} [position] - The relative position of the item.
  1161 + * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
  1162 + */
  1163 + Owl.prototype.items = function(position) {
  1164 + if (position === undefined) {
  1165 + return this._items.slice();
  1166 + }
  1167 +
  1168 + position = this.normalize(position, true);
  1169 + return this._items[position];
  1170 + };
  1171 +
  1172 + /**
  1173 + * Gets an item at the specified relative position.
  1174 + * @public
  1175 + * @param {Number} [position] - The relative position of the item.
  1176 + * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
  1177 + */
  1178 + Owl.prototype.mergers = function(position) {
  1179 + if (position === undefined) {
  1180 + return this._mergers.slice();
  1181 + }
  1182 +
  1183 + position = this.normalize(position, true);
  1184 + return this._mergers[position];
  1185 + };
  1186 +
  1187 + /**
  1188 + * Gets the absolute positions of clones for an item.
  1189 + * @public
  1190 + * @param {Number} [position] - The relative position of the item.
  1191 + * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
  1192 + */
  1193 + Owl.prototype.clones = function(position) {
  1194 + var odd = this._clones.length / 2,
  1195 + even = odd + this._items.length,
  1196 + map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
  1197 +
  1198 + if (position === undefined) {
  1199 + return $.map(this._clones, function(v, i) { return map(i) });
  1200 + }
  1201 +
  1202 + return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
  1203 + };
  1204 +
  1205 + /**
  1206 + * Sets the current animation speed.
  1207 + * @public
  1208 + * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
  1209 + * @returns {Number} - The current animation speed in milliseconds.
  1210 + */
  1211 + Owl.prototype.speed = function(speed) {
  1212 + if (speed !== undefined) {
  1213 + this._speed = speed;
  1214 + }
  1215 +
  1216 + return this._speed;
  1217 + };
  1218 +
  1219 + /**
  1220 + * Gets the coordinate of an item.
  1221 + * @todo The name of this method is missleanding.
  1222 + * @public
  1223 + * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
  1224 + * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
  1225 + */
  1226 + Owl.prototype.coordinates = function(position) {
  1227 + var coordinate = null;
  1228 +
  1229 + if (position === undefined) {
  1230 + return $.map(this._coordinates, $.proxy(function(coordinate, index) {
  1231 + return this.coordinates(index);
  1232 + }, this));
  1233 + }
  1234 +
  1235 + if (this.settings.center) {
  1236 + coordinate = this._coordinates[position];
  1237 + coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
  1238 + } else {
  1239 + coordinate = this._coordinates[position - 1] || 0;
  1240 + }
  1241 +
  1242 + return coordinate;
  1243 + };
  1244 +
  1245 + /**
  1246 + * Calculates the speed for a translation.
  1247 + * @protected
  1248 + * @param {Number} from - The absolute position of the start item.
  1249 + * @param {Number} to - The absolute position of the target item.
  1250 + * @param {Number} [factor=undefined] - The time factor in milliseconds.
  1251 + * @returns {Number} - The time in milliseconds for the translation.
  1252 + */
  1253 + Owl.prototype.duration = function(from, to, factor) {
  1254 + return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
  1255 + };
  1256 +
  1257 + /**
  1258 + * Slides to the specified item.
  1259 + * @public
  1260 + * @param {Number} position - The position of the item.
  1261 + * @param {Number} [speed] - The time in milliseconds for the transition.
  1262 + */
  1263 + Owl.prototype.to = function(position, speed) {
  1264 + if (this.settings.loop) {
  1265 + var distance = position - this.relative(this.current()),
  1266 + revert = this.current(),
  1267 + before = this.current(),
  1268 + after = this.current() + distance,
  1269 + direction = before - after < 0 ? true : false,
  1270 + items = this._clones.length + this._items.length;
  1271 +
  1272 + if (after < this.settings.items && direction === false) {
  1273 + revert = before + this._items.length;
  1274 + this.reset(revert);
  1275 + } else if (after >= items - this.settings.items && direction === true) {
  1276 + revert = before - this._items.length;
  1277 + this.reset(revert);
  1278 + }
  1279 + window.clearTimeout(this.e._goToLoop);
  1280 + this.e._goToLoop = window.setTimeout($.proxy(function() {
  1281 + this.speed(this.duration(this.current(), revert + distance, speed));
  1282 + this.current(revert + distance);
  1283 + this.update();
  1284 + }, this), 30);
  1285 + } else {
  1286 + this.speed(this.duration(this.current(), position, speed));
  1287 + this.current(position);
  1288 + this.update();
  1289 + }
  1290 + };
  1291 +
  1292 + /**
  1293 + * Slides to the next item.
  1294 + * @public
  1295 + * @param {Number} [speed] - The time in milliseconds for the transition.
  1296 + */
  1297 + Owl.prototype.next = function(speed) {
  1298 + speed = speed || false;
  1299 + this.to(this.relative(this.current()) + 1, speed);
  1300 + };
  1301 +
  1302 + /**
  1303 + * Slides to the previous item.
  1304 + * @public
  1305 + * @param {Number} [speed] - The time in milliseconds for the transition.
  1306 + */
  1307 + Owl.prototype.prev = function(speed) {
  1308 + speed = speed || false;
  1309 + this.to(this.relative(this.current()) - 1, speed);
  1310 + };
  1311 +
  1312 + /**
  1313 + * Handles the end of an animation.
  1314 + * @protected
  1315 + * @param {Event} event - The event arguments.
  1316 + */
  1317 + Owl.prototype.transitionEnd = function(event) {
  1318 +
  1319 + // if css2 animation then event object is undefined
  1320 + if (event !== undefined) {
  1321 + event.stopPropagation();
  1322 +
  1323 + // Catch only owl-stage transitionEnd event
  1324 + if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
  1325 + return false;
  1326 + }
  1327 + }
  1328 +
  1329 + this.state.inMotion = false;
  1330 + this.trigger('translated');
  1331 + };
  1332 +
  1333 + /**
  1334 + * Gets viewport width.
  1335 + * @protected
  1336 + * @return {Number} - The width in pixel.
  1337 + */
  1338 + Owl.prototype.viewport = function() {
  1339 + var width;
  1340 + if (this.options.responsiveBaseElement !== window) {
  1341 + width = $(this.options.responsiveBaseElement).width();
  1342 + } else if (window.innerWidth) {
  1343 + width = window.innerWidth;
  1344 + } else if (document.documentElement && document.documentElement.clientWidth) {
  1345 + width = document.documentElement.clientWidth;
  1346 + } else {
  1347 + throw 'Can not detect viewport width.';
  1348 + }
  1349 + return width;
  1350 + };
  1351 +
  1352 + /**
  1353 + * Replaces the current content.
  1354 + * @public
  1355 + * @param {HTMLElement|jQuery|String} content - The new content.
  1356 + */
  1357 + Owl.prototype.replace = function(content) {
  1358 + this.$stage.empty();
  1359 + this._items = [];
  1360 +
  1361 + if (content) {
  1362 + content = (content instanceof jQuery) ? content : $(content);
  1363 + }
  1364 +
  1365 + if (this.settings.nestedItemSelector) {
  1366 + content = content.find('.' + this.settings.nestedItemSelector);
  1367 + }
  1368 +
  1369 + content.filter(function() {
  1370 + return this.nodeType === 1;
  1371 + }).each($.proxy(function(index, item) {
  1372 + item = this.prepare(item);
  1373 + this.$stage.append(item);
  1374 + this._items.push(item);
  1375 + this._mergers.push(item.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
  1376 + }, this));
  1377 +
  1378 + this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
  1379 +
  1380 + this.invalidate('items');
  1381 + };
  1382 +
  1383 + /**
  1384 + * Adds an item.
  1385 + * @todo Use `item` instead of `content` for the event arguments.
  1386 + * @public
  1387 + * @param {HTMLElement|jQuery|String} content - The item content to add.
  1388 + * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
  1389 + */
  1390 + Owl.prototype.add = function(content, position) {
  1391 + position = position === undefined ? this._items.length : this.normalize(position, true);
  1392 +
  1393 + this.trigger('add', { content: content, position: position });
  1394 +
  1395 + if (this._items.length === 0 || position === this._items.length) {
  1396 + this.$stage.append(content);
  1397 + this._items.push(content);
  1398 + this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
  1399 + } else {
  1400 + this._items[position].before(content);
  1401 + this._items.splice(position, 0, content);
  1402 + this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
  1403 + }
  1404 +
  1405 + this.invalidate('items');
  1406 +
  1407 + this.trigger('added', { content: content, position: position });
  1408 + };
  1409 +
  1410 + /**
  1411 + * Removes an item by its position.
  1412 + * @todo Use `item` instead of `content` for the event arguments.
  1413 + * @public
  1414 + * @param {Number} position - The relative position of the item to remove.
  1415 + */
  1416 + Owl.prototype.remove = function(position) {
  1417 + position = this.normalize(position, true);
  1418 +
  1419 + if (position === undefined) {
  1420 + return;
  1421 + }
  1422 +
  1423 + this.trigger('remove', { content: this._items[position], position: position });
  1424 +
  1425 + this._items[position].remove();
  1426 + this._items.splice(position, 1);
  1427 + this._mergers.splice(position, 1);
  1428 +
  1429 + this.invalidate('items');
  1430 +
  1431 + this.trigger('removed', { content: null, position: position });
  1432 + };
  1433 +
  1434 + /**
  1435 + * Adds triggerable events.
  1436 + * @protected
  1437 + */
  1438 + Owl.prototype.addTriggerableEvents = function() {
  1439 + var handler = $.proxy(function(callback, event) {
  1440 + return $.proxy(function(e) {
  1441 + if (e.relatedTarget !== this) {
  1442 + this.suppress([ event ]);
  1443 + callback.apply(this, [].slice.call(arguments, 1));
  1444 + this.release([ event ]);
  1445 + }
  1446 + }, this);
  1447 + }, this);
  1448 +
  1449 + $.each({
  1450 + 'next': this.next,
  1451 + 'prev': this.prev,
  1452 + 'to': this.to,
  1453 + 'destroy': this.destroy,
  1454 + 'refresh': this.refresh,
  1455 + 'replace': this.replace,
  1456 + 'add': this.add,
  1457 + 'remove': this.remove
  1458 + }, $.proxy(function(event, callback) {
  1459 + this.$element.on(event + '.owl.carousel', handler(callback, event + '.owl.carousel'));
  1460 + }, this));
  1461 +
  1462 + };
  1463 +
  1464 + /**
  1465 + * Watches the visibility of the carousel element.
  1466 + * @protected
  1467 + */
  1468 + Owl.prototype.watchVisibility = function() {
  1469 +
  1470 + // test on zepto
  1471 + if (!isElVisible(this.$element.get(0))) {
  1472 + this.$element.addClass('owl-hidden');
  1473 + window.clearInterval(this.e._checkVisibile);
  1474 + this.e._checkVisibile = window.setInterval($.proxy(checkVisible, this), 500);
  1475 + }
  1476 +
  1477 + function isElVisible(el) {
  1478 + return el.offsetWidth > 0 && el.offsetHeight > 0;
  1479 + }
  1480 +
  1481 + function checkVisible() {
  1482 + if (isElVisible(this.$element.get(0))) {
  1483 + this.$element.removeClass('owl-hidden');
  1484 + this.refresh();
  1485 + window.clearInterval(this.e._checkVisibile);
  1486 + }
  1487 + }
  1488 + };
  1489 +
  1490 + /**
  1491 + * Preloads images with auto width.
  1492 + * @protected
  1493 + * @todo Still to test
  1494 + */
  1495 + Owl.prototype.preloadAutoWidthImages = function(imgs) {
  1496 + var loaded, that, $el, img;
  1497 +
  1498 + loaded = 0;
  1499 + that = this;
  1500 + imgs.each(function(i, el) {
  1501 + $el = $(el);
  1502 + img = new Image();
  1503 +
  1504 + img.onload = function() {
  1505 + loaded++;
  1506 + $el.attr('src', img.src);
  1507 + $el.css('opacity', 1);
  1508 + if (loaded >= imgs.length) {
  1509 + that.state.imagesLoaded = true;
  1510 + that.initialize();
  1511 + }
  1512 + };
  1513 +
  1514 + img.src = $el.attr('src') || $el.attr('data-src') || $el.attr('data-src-retina');
  1515 + });
  1516 + };
  1517 +
  1518 + /**
  1519 + * Destroys the carousel.
  1520 + * @public
  1521 + */
  1522 + Owl.prototype.destroy = function() {
  1523 +
  1524 + if (this.$element.hasClass(this.settings.themeClass)) {
  1525 + this.$element.removeClass(this.settings.themeClass);
  1526 + }
  1527 +
  1528 + if (this.settings.responsive !== false) {
  1529 + $(window).off('resize.owl.carousel');
  1530 + }
  1531 +
  1532 + if (this.transitionEndVendor) {
  1533 + this.off(this.$stage.get(0), this.transitionEndVendor, this.e._transitionEnd);
  1534 + }
  1535 +
  1536 + for ( var i in this._plugins) {
  1537 + this._plugins[i].destroy();
  1538 + }
  1539 +
  1540 + if (this.settings.mouseDrag || this.settings.touchDrag) {
  1541 + this.$stage.off('mousedown touchstart touchcancel');
  1542 + $(document).off('.owl.dragEvents');
  1543 + this.$stage.get(0).onselectstart = function() {};
  1544 + this.$stage.off('dragstart', function() { return false });
  1545 + }
  1546 +
  1547 + // remove event handlers in the ".owl.carousel" namespace
  1548 + this.$element.off('.owl');
  1549 +
  1550 + this.$stage.children('.cloned').remove();
  1551 + this.e = null;
  1552 + this.$element.removeData('owlCarousel');
  1553 +
  1554 + this.$stage.children().contents().unwrap();
  1555 + this.$stage.children().unwrap();
  1556 + this.$stage.unwrap();
  1557 + };
  1558 +
  1559 + /**
  1560 + * Operators to calculate right-to-left and left-to-right.
  1561 + * @protected
  1562 + * @param {Number} [a] - The left side operand.
  1563 + * @param {String} [o] - The operator.
  1564 + * @param {Number} [b] - The right side operand.
  1565 + */
  1566 + Owl.prototype.op = function(a, o, b) {
  1567 + var rtl = this.settings.rtl;
  1568 + switch (o) {
  1569 + case '<':
  1570 + return rtl ? a > b : a < b;
  1571 + case '>':
  1572 + return rtl ? a < b : a > b;
  1573 + case '>=':
  1574 + return rtl ? a <= b : a >= b;
  1575 + case '<=':
  1576 + return rtl ? a >= b : a <= b;
  1577 + default:
  1578 + break;
  1579 + }
  1580 + };
  1581 +
  1582 + /**
  1583 + * Attaches to an internal event.
  1584 + * @protected
  1585 + * @param {HTMLElement} element - The event source.
  1586 + * @param {String} event - The event name.
  1587 + * @param {Function} listener - The event handler to attach.
  1588 + * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
  1589 + */
  1590 + Owl.prototype.on = function(element, event, listener, capture) {
  1591 + if (element.addEventListener) {
  1592 + element.addEventListener(event, listener, capture);
  1593 + } else if (element.attachEvent) {
  1594 + element.attachEvent('on' + event, listener);
  1595 + }
  1596 + };
  1597 +
  1598 + /**
  1599 + * Detaches from an internal event.
  1600 + * @protected
  1601 + * @param {HTMLElement} element - The event source.
  1602 + * @param {String} event - The event name.
  1603 + * @param {Function} listener - The attached event handler to detach.
  1604 + * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
  1605 + */
  1606 + Owl.prototype.off = function(element, event, listener, capture) {
  1607 + if (element.removeEventListener) {
  1608 + element.removeEventListener(event, listener, capture);
  1609 + } else if (element.detachEvent) {
  1610 + element.detachEvent('on' + event, listener);
  1611 + }
  1612 + };
  1613 +
  1614 + /**
  1615 + * Triggers an public event.
  1616 + * @protected
  1617 + * @param {String} name - The event name.
  1618 + * @param {*} [data=null] - The event data.
  1619 + * @param {String} [namespace=.owl.carousel] - The event namespace.
  1620 + * @returns {Event} - The event arguments.
  1621 + */
  1622 + Owl.prototype.trigger = function(name, data, namespace) {
  1623 + var status = {
  1624 + item: { count: this._items.length, index: this.current() }
  1625 + }, handler = $.camelCase(
  1626 + $.grep([ 'on', name, namespace ], function(v) { return v })
  1627 + .join('-').toLowerCase()
  1628 + ), event = $.Event(
  1629 + [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
  1630 + $.extend({ relatedTarget: this }, status, data)
  1631 + );
  1632 +
  1633 + if (!this._supress[name]) {
  1634 + $.each(this._plugins, function(name, plugin) {
  1635 + if (plugin.onTrigger) {
  1636 + plugin.onTrigger(event);
  1637 + }
  1638 + });
  1639 +
  1640 + this.$element.trigger(event);
  1641 +
  1642 + if (this.settings && typeof this.settings[handler] === 'function') {
  1643 + this.settings[handler].apply(this, event);
  1644 + }
  1645 + }
  1646 +
  1647 + return event;
  1648 + };
  1649 +
  1650 + /**
  1651 + * Suppresses events.
  1652 + * @protected
  1653 + * @param {Array.<String>} events - The events to suppress.
  1654 + */
  1655 + Owl.prototype.suppress = function(events) {
  1656 + $.each(events, $.proxy(function(index, event) {
  1657 + this._supress[event] = true;
  1658 + }, this));
  1659 + }
  1660 +
  1661 + /**
  1662 + * Releases suppressed events.
  1663 + * @protected
  1664 + * @param {Array.<String>} events - The events to release.
  1665 + */
  1666 + Owl.prototype.release = function(events) {
  1667 + $.each(events, $.proxy(function(index, event) {
  1668 + delete this._supress[event];
  1669 + }, this));
  1670 + }
  1671 +
  1672 + /**
  1673 + * Checks the availability of some browser features.
  1674 + * @protected
  1675 + */
  1676 + Owl.prototype.browserSupport = function() {
  1677 + this.support3d = isPerspective();
  1678 +
  1679 + if (this.support3d) {
  1680 + this.transformVendor = isTransform();
  1681 +
  1682 + // take transitionend event name by detecting transition
  1683 + var endVendors = [ 'transitionend', 'webkitTransitionEnd', 'transitionend', 'oTransitionEnd' ];
  1684 + this.transitionEndVendor = endVendors[isTransition()];
  1685 +
  1686 + // take vendor name from transform name
  1687 + this.vendorName = this.transformVendor.replace(/Transform/i, '');
  1688 + this.vendorName = this.vendorName !== '' ? '-' + this.vendorName.toLowerCase() + '-' : '';
  1689 + }
  1690 +
  1691 + this.state.orientation = window.orientation;
  1692 + };
  1693 +
  1694 + /**
  1695 + * Get touch/drag coordinats.
  1696 + * @private
  1697 + * @param {event} - mousedown/touchstart event
  1698 + * @returns {object} - Contains X and Y of current mouse/touch position
  1699 + */
  1700 +
  1701 + function getTouches(event) {
  1702 + if (event.touches !== undefined) {
  1703 + return {
  1704 + x: event.touches[0].pageX,
  1705 + y: event.touches[0].pageY
  1706 + };
  1707 + }
  1708 +
  1709 + if (event.touches === undefined) {
  1710 + if (event.pageX !== undefined) {
  1711 + return {
  1712 + x: event.pageX,
  1713 + y: event.pageY
  1714 + };
  1715 + }
  1716 +
  1717 + if (event.pageX === undefined) {
  1718 + return {
  1719 + x: event.clientX,
  1720 + y: event.clientY
  1721 + };
  1722 + }
  1723 + }
  1724 + }
  1725 +
  1726 + /**
  1727 + * Checks for CSS support.
  1728 + * @private
  1729 + * @param {Array} array - The CSS properties to check for.
  1730 + * @returns {Array} - Contains the supported CSS property name and its index or `false`.
  1731 + */
  1732 + function isStyleSupported(array) {
  1733 + var p, s, fake = document.createElement('div'), list = array;
  1734 + for (p in list) {
  1735 + s = list[p];
  1736 + if (typeof fake.style[s] !== 'undefined') {
  1737 + fake = null;
  1738 + return [ s, p ];
  1739 + }
  1740 + }
  1741 + return [ false ];
  1742 + }
  1743 +
  1744 + /**
  1745 + * Checks for CSS transition support.
  1746 + * @private
  1747 + * @todo Realy bad design
  1748 + * @returns {Number}
  1749 + */
  1750 + function isTransition() {
  1751 + return isStyleSupported([ 'transition', 'WebkitTransition', 'MozTransition', 'OTransition' ])[1];
  1752 + }
  1753 +
  1754 + /**
  1755 + * Checks for CSS transform support.
  1756 + * @private
  1757 + * @returns {String} The supported property name or false.
  1758 + */
  1759 + function isTransform() {
  1760 + return isStyleSupported([ 'transform', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ])[0];
  1761 + }
  1762 +
  1763 + /**
  1764 + * Checks for CSS perspective support.
  1765 + * @private
  1766 + * @returns {String} The supported property name or false.
  1767 + */
  1768 + function isPerspective() {
  1769 + return isStyleSupported([ 'perspective', 'webkitPerspective', 'MozPerspective', 'OPerspective', 'MsPerspective' ])[0];
  1770 + }
  1771 +
  1772 + /**
  1773 + * Checks wether touch is supported or not.
  1774 + * @private
  1775 + * @returns {Boolean}
  1776 + */
  1777 + function isTouchSupport() {
  1778 + return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);
  1779 + }
  1780 +
  1781 + /**
  1782 + * Checks wether touch is supported or not for IE.
  1783 + * @private
  1784 + * @returns {Boolean}
  1785 + */
  1786 + function isTouchSupportIE() {
  1787 + return window.navigator.msPointerEnabled;
  1788 + }
  1789 +
  1790 + /**
  1791 + * The jQuery Plugin for the Owl Carousel
  1792 + * @public
  1793 + */
  1794 + $.fn.owlCarousel = function(options) {
  1795 + return this.each(function() {
  1796 + if (!$(this).data('owlCarousel')) {
  1797 + $(this).data('owlCarousel', new Owl(this, options));
  1798 + }
  1799 + });
  1800 + };
  1801 +
  1802 + /**
  1803 + * The constructor for the jQuery Plugin
  1804 + * @public
  1805 + */
  1806 + $.fn.owlCarousel.Constructor = Owl;
  1807 +
  1808 +})(window.Zepto || window.jQuery, window, document);
  1809 +
  1810 +/**
  1811 + * Lazy Plugin
  1812 + * @version 2.0.0
  1813 + * @author Bartosz Wojciechowski
  1814 + * @license The MIT License (MIT)
  1815 + */
  1816 +;(function($, window, document, undefined) {
  1817 +
  1818 + /**
  1819 + * Creates the lazy plugin.
  1820 + * @class The Lazy Plugin
  1821 + * @param {Owl} carousel - The Owl Carousel
  1822 + */
  1823 + var Lazy = function(carousel) {
  1824 +
  1825 + /**
  1826 + * Reference to the core.
  1827 + * @protected
  1828 + * @type {Owl}
  1829 + */
  1830 + this._core = carousel;
  1831 +
  1832 + /**
  1833 + * Already loaded items.
  1834 + * @protected
  1835 + * @type {Array.<jQuery>}
  1836 + */
  1837 + this._loaded = [];
  1838 +
  1839 + /**
  1840 + * Event handlers.
  1841 + * @protected
  1842 + * @type {Object}
  1843 + */
  1844 + this._handlers = {
  1845 + 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
  1846 + if (!e.namespace) {
  1847 + return;
  1848 + }
  1849 +
  1850 + if (!this._core.settings || !this._core.settings.lazyLoad) {
  1851 + return;
  1852 + }
  1853 +
  1854 + if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
  1855 + var settings = this._core.settings,
  1856 + n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
  1857 + i = ((settings.center && n * -1) || 0),
  1858 + position = ((e.property && e.property.value) || this._core.current()) + i,
  1859 + clones = this._core.clones().length,
  1860 + load = $.proxy(function(i, v) { this.load(v) }, this);
  1861 +
  1862 + while (i++ < n) {
  1863 + this.load(clones / 2 + this._core.relative(position));
  1864 + clones && $.each(this._core.clones(this._core.relative(position++)), load);
  1865 + }
  1866 + }
  1867 + }, this)
  1868 + };
  1869 +
  1870 + // set the default options
  1871 + this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
  1872 +
  1873 + // register event handler
  1874 + this._core.$element.on(this._handlers);
  1875 + }
  1876 +
  1877 + /**
  1878 + * Default options.
  1879 + * @public
  1880 + */
  1881 + Lazy.Defaults = {
  1882 + lazyLoad: false
  1883 + }
  1884 +
  1885 + /**
  1886 + * Loads all resources of an item at the specified position.
  1887 + * @param {Number} position - The absolute position of the item.
  1888 + * @protected
  1889 + */
  1890 + Lazy.prototype.load = function(position) {
  1891 + var $item = this._core.$stage.children().eq(position),
  1892 + $elements = $item && $item.find('.owl-lazy');
  1893 +
  1894 + if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
  1895 + return;
  1896 + }
  1897 +
  1898 + $elements.each($.proxy(function(index, element) {
  1899 + var $element = $(element), image,
  1900 + url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
  1901 +
  1902 + this._core.trigger('load', { element: $element, url: url }, 'lazy');
  1903 +
  1904 + if ($element.is('img')) {
  1905 + $element.one('load.owl.lazy', $.proxy(function() {
  1906 + $element.css('opacity', 1);
  1907 + this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
  1908 + }, this)).attr('src', url);
  1909 + } else {
  1910 + image = new Image();
  1911 + image.onload = $.proxy(function() {
  1912 + $element.css({
  1913 + 'background-image': 'url(' + url + ')',
  1914 + 'opacity': '1'
  1915 + });
  1916 + this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
  1917 + }, this);
  1918 + image.src = url;
  1919 + }
  1920 + }, this));
  1921 +
  1922 + this._loaded.push($item.get(0));
  1923 + }
  1924 +
  1925 + /**
  1926 + * Destroys the plugin.
  1927 + * @public
  1928 + */
  1929 + Lazy.prototype.destroy = function() {
  1930 + var handler, property;
  1931 +
  1932 + for (handler in this.handlers) {
  1933 + this._core.$element.off(handler, this.handlers[handler]);
  1934 + }
  1935 + for (property in Object.getOwnPropertyNames(this)) {
  1936 + typeof this[property] != 'function' && (this[property] = null);
  1937 + }
  1938 + }
  1939 +
  1940 + $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
  1941 +
  1942 +})(window.Zepto || window.jQuery, window, document);
  1943 +
  1944 +/**
  1945 + * AutoHeight Plugin
  1946 + * @version 2.0.0
  1947 + * @author Bartosz Wojciechowski
  1948 + * @license The MIT License (MIT)
  1949 + */
  1950 +;(function($, window, document, undefined) {
  1951 +
  1952 + /**
  1953 + * Creates the auto height plugin.
  1954 + * @class The Auto Height Plugin
  1955 + * @param {Owl} carousel - The Owl Carousel
  1956 + */
  1957 + var AutoHeight = function(carousel) {
  1958 + /**
  1959 + * Reference to the core.
  1960 + * @protected
  1961 + * @type {Owl}
  1962 + */
  1963 + this._core = carousel;
  1964 +
  1965 + /**
  1966 + * All event handlers.
  1967 + * @protected
  1968 + * @type {Object}
  1969 + */
  1970 + this._handlers = {
  1971 + 'initialized.owl.carousel': $.proxy(function() {
  1972 + if (this._core.settings.autoHeight) {
  1973 + this.update();
  1974 + }
  1975 + }, this),
  1976 + 'changed.owl.carousel': $.proxy(function(e) {
  1977 + if (this._core.settings.autoHeight && e.property.name == 'position'){
  1978 + this.update();
  1979 + }
  1980 + }, this),
  1981 + 'loaded.owl.lazy': $.proxy(function(e) {
  1982 + if (this._core.settings.autoHeight && e.element.closest('.' + this._core.settings.itemClass)
  1983 + === this._core.$stage.children().eq(this._core.current())) {
  1984 + this.update();
  1985 + }
  1986 + }, this)
  1987 + };
  1988 +
  1989 + // set default options
  1990 + this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
  1991 +
  1992 + // register event handlers
  1993 + this._core.$element.on(this._handlers);
  1994 + };
  1995 +
  1996 + /**
  1997 + * Default options.
  1998 + * @public
  1999 + */
  2000 + AutoHeight.Defaults = {
  2001 + autoHeight: false,
  2002 + autoHeightClass: 'owl-height'
  2003 + };
  2004 +
  2005 + /**
  2006 + * Updates the view.
  2007 + */
  2008 + AutoHeight.prototype.update = function() {
  2009 + this._core.$stage.parent()
  2010 + .height(this._core.$stage.children().eq(this._core.current()).height())
  2011 + .addClass(this._core.settings.autoHeightClass);
  2012 + };
  2013 +
  2014 + AutoHeight.prototype.destroy = function() {
  2015 + var handler, property;
  2016 +
  2017 + for (handler in this._handlers) {
  2018 + this._core.$element.off(handler, this._handlers[handler]);
  2019 + }
  2020 + for (property in Object.getOwnPropertyNames(this)) {
  2021 + typeof this[property] != 'function' && (this[property] = null);
  2022 + }
  2023 + };
  2024 +
  2025 + $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
  2026 +
  2027 +})(window.Zepto || window.jQuery, window, document);
  2028 +
  2029 +/**
  2030 + * Video Plugin
  2031 + * @version 2.0.0
  2032 + * @author Bartosz Wojciechowski
  2033 + * @license The MIT License (MIT)
  2034 + */
  2035 +;(function($, window, document, undefined) {
  2036 +
  2037 + /**
  2038 + * Creates the video plugin.
  2039 + * @class The Video Plugin
  2040 + * @param {Owl} carousel - The Owl Carousel
  2041 + */
  2042 + var Video = function(carousel) {
  2043 + /**
  2044 + * Reference to the core.
  2045 + * @protected
  2046 + * @type {Owl}
  2047 + */
  2048 + this._core = carousel;
  2049 +
  2050 + /**
  2051 + * Cache all video URLs.
  2052 + * @protected
  2053 + * @type {Object}
  2054 + */
  2055 + this._videos = {};
  2056 +
  2057 + /**
  2058 + * Current playing item.
  2059 + * @protected
  2060 + * @type {jQuery}
  2061 + */
  2062 + this._playing = null;
  2063 +
  2064 + /**
  2065 + * Whether this is in fullscreen or not.
  2066 + * @protected
  2067 + * @type {Boolean}
  2068 + */
  2069 + this._fullscreen = false;
  2070 +
  2071 + /**
  2072 + * All event handlers.
  2073 + * @protected
  2074 + * @type {Object}
  2075 + */
  2076 + this._handlers = {
  2077 + 'resize.owl.carousel': $.proxy(function(e) {
  2078 + if (this._core.settings.video && !this.isInFullScreen()) {
  2079 + e.preventDefault();
  2080 + }
  2081 + }, this),
  2082 + 'refresh.owl.carousel changed.owl.carousel': $.proxy(function(e) {
  2083 + if (this._playing) {
  2084 + this.stop();
  2085 + }
  2086 + }, this),
  2087 + 'prepared.owl.carousel': $.proxy(function(e) {
  2088 + var $element = $(e.content).find('.owl-video');
  2089 + if ($element.length) {
  2090 + $element.css('display', 'none');
  2091 + this.fetch($element, $(e.content));
  2092 + }
  2093 + }, this)
  2094 + };
  2095 +
  2096 + // set default options
  2097 + this._core.options = $.extend({}, Video.Defaults, this._core.options);
  2098 +
  2099 + // register event handlers
  2100 + this._core.$element.on(this._handlers);
  2101 +
  2102 + this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
  2103 + this.play(e);
  2104 + }, this));
  2105 + };
  2106 +
  2107 + /**
  2108 + * Default options.
  2109 + * @public
  2110 + */
  2111 + Video.Defaults = {
  2112 + video: false,
  2113 + videoHeight: false,
  2114 + videoWidth: false
  2115 + };
  2116 +
  2117 + /**
  2118 + * Gets the video ID and the type (YouTube/Vimeo only).
  2119 + * @protected
  2120 + * @param {jQuery} target - The target containing the video data.
  2121 + * @param {jQuery} item - The item containing the video.
  2122 + */
  2123 + Video.prototype.fetch = function(target, item) {
  2124 +
  2125 + var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
  2126 + id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
  2127 + width = target.attr('data-width') || this._core.settings.videoWidth,
  2128 + height = target.attr('data-height') || this._core.settings.videoHeight,
  2129 + url = target.attr('href');
  2130 +
  2131 + if (url) {
  2132 + id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
  2133 +
  2134 + if (id[3].indexOf('youtu') > -1) {
  2135 + type = 'youtube';
  2136 + } else if (id[3].indexOf('vimeo') > -1) {
  2137 + type = 'vimeo';
  2138 + } else {
  2139 + throw new Error('Video URL not supported.');
  2140 + }
  2141 + id = id[6];
  2142 + } else {
  2143 + throw new Error('Missing video URL.');
  2144 + }
  2145 +
  2146 + this._videos[url] = {
  2147 + type: type,
  2148 + id: id,
  2149 + width: width,
  2150 + height: height
  2151 + };
  2152 +
  2153 + item.attr('data-video', url);
  2154 +
  2155 + this.thumbnail(target, this._videos[url]);
  2156 + };
  2157 +
  2158 + /**
  2159 + * Creates video thumbnail.
  2160 + * @protected
  2161 + * @param {jQuery} target - The target containing the video data.
  2162 + * @param {Object} info - The video info object.
  2163 + * @see `fetch`
  2164 + */
  2165 + Video.prototype.thumbnail = function(target, video) {
  2166 +
  2167 + var tnLink,
  2168 + icon,
  2169 + path,
  2170 + dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
  2171 + customTn = target.find('img'),
  2172 + srcType = 'src',
  2173 + lazyClass = '',
  2174 + settings = this._core.settings,
  2175 + create = function(path) {
  2176 + icon = '<div class="owl-video-play-icon"></div>';
  2177 +
  2178 + if (settings.lazyLoad) {
  2179 + tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
  2180 + } else {
  2181 + tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
  2182 + }
  2183 + target.after(tnLink);
  2184 + target.after(icon);
  2185 + };
  2186 +
  2187 + // wrap video content into owl-video-wrapper div
  2188 + target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
  2189 +
  2190 + if (this._core.settings.lazyLoad) {
  2191 + srcType = 'data-src';
  2192 + lazyClass = 'owl-lazy';
  2193 + }
  2194 +
  2195 + // custom thumbnail
  2196 + if (customTn.length) {
  2197 + create(customTn.attr(srcType));
  2198 + customTn.remove();
  2199 + return false;
  2200 + }
  2201 +
  2202 + if (video.type === 'youtube') {
  2203 + path = "http://img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
  2204 + create(path);
  2205 + } else if (video.type === 'vimeo') {
  2206 + $.ajax({
  2207 + type: 'GET',
  2208 + url: 'http://vimeo.com/api/v2/video/' + video.id + '.json',
  2209 + jsonp: 'callback',
  2210 + dataType: 'jsonp',
  2211 + success: function(data) {
  2212 + path = data[0].thumbnail_large;
  2213 + create(path);
  2214 + }
  2215 + });
  2216 + }
  2217 + };
  2218 +
  2219 + /**
  2220 + * Stops the current video.
  2221 + * @public
  2222 + */
  2223 + Video.prototype.stop = function() {
  2224 + this._core.trigger('stop', null, 'video');
  2225 + this._playing.find('.owl-video-frame').remove();
  2226 + this._playing.removeClass('owl-video-playing');
  2227 + this._playing = null;
  2228 + };
  2229 +
  2230 + /**
  2231 + * Starts the current video.
  2232 + * @public
  2233 + * @param {Event} ev - The event arguments.
  2234 + */
  2235 + Video.prototype.play = function(ev) {
  2236 + this._core.trigger('play', null, 'video');
  2237 +
  2238 + if (this._playing) {
  2239 + this.stop();
  2240 + }
  2241 +
  2242 + var target = $(ev.target || ev.srcElement),
  2243 + item = target.closest('.' + this._core.settings.itemClass),
  2244 + video = this._videos[item.attr('data-video')],
  2245 + width = video.width || '100%',
  2246 + height = video.height || this._core.$stage.height(),
  2247 + html, wrap;
  2248 +
  2249 + if (video.type === 'youtube') {
  2250 + html = '<iframe width="' + width + '" height="' + height + '" src="http://www.youtube.com/embed/'
  2251 + + video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
  2252 + } else if (video.type === 'vimeo') {
  2253 + html = '<iframe src="http://player.vimeo.com/video/' + video.id + '?autoplay=1" width="' + width
  2254 + + '" height="' + height
  2255 + + '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
  2256 + }
  2257 +
  2258 + item.addClass('owl-video-playing');
  2259 + this._playing = item;
  2260 +
  2261 + wrap = $('<div style="height:' + height + 'px; width:' + width + 'px" class="owl-video-frame">'
  2262 + + html + '</div>');
  2263 + target.after(wrap);
  2264 + };
  2265 +
  2266 + /**
  2267 + * Checks whether an video is currently in full screen mode or not.
  2268 + * @todo Bad style because looks like a readonly method but changes members.
  2269 + * @protected
  2270 + * @returns {Boolean}
  2271 + */
  2272 + Video.prototype.isInFullScreen = function() {
  2273 +
  2274 + // if Vimeo Fullscreen mode
  2275 + var element = document.fullscreenElement || document.mozFullScreenElement
  2276 + || document.webkitFullscreenElement;
  2277 +
  2278 + if (element && $(element).parent().hasClass('owl-video-frame')) {
  2279 + this._core.speed(0);
  2280 + this._fullscreen = true;
  2281 + }
  2282 +
  2283 + if (element && this._fullscreen && this._playing) {
  2284 + return false;
  2285 + }
  2286 +
  2287 + // comming back from fullscreen
  2288 + if (this._fullscreen) {
  2289 + this._fullscreen = false;
  2290 + return false;
  2291 + }
  2292 +
  2293 + // check full screen mode and window orientation
  2294 + if (this._playing) {
  2295 + if (this._core.state.orientation !== window.orientation) {
  2296 + this._core.state.orientation = window.orientation;
  2297 + return false;
  2298 + }
  2299 + }
  2300 +
  2301 + return true;
  2302 + };
  2303 +
  2304 + /**
  2305 + * Destroys the plugin.
  2306 + */
  2307 + Video.prototype.destroy = function() {
  2308 + var handler, property;
  2309 +
  2310 + this._core.$element.off('click.owl.video');
  2311 +
  2312 + for (handler in this._handlers) {
  2313 + this._core.$element.off(handler, this._handlers[handler]);
  2314 + }
  2315 + for (property in Object.getOwnPropertyNames(this)) {
  2316 + typeof this[property] != 'function' && (this[property] = null);
  2317 + }
  2318 + };
  2319 +
  2320 + $.fn.owlCarousel.Constructor.Plugins.Video = Video;
  2321 +
  2322 +})(window.Zepto || window.jQuery, window, document);
  2323 +
  2324 +/**
  2325 + * Animate Plugin
  2326 + * @version 2.0.0
  2327 + * @author Bartosz Wojciechowski
  2328 + * @license The MIT License (MIT)
  2329 + */
  2330 +;(function($, window, document, undefined) {
  2331 +
  2332 + /**
  2333 + * Creates the animate plugin.
  2334 + * @class The Navigation Plugin
  2335 + * @param {Owl} scope - The Owl Carousel
  2336 + */
  2337 + var Animate = function(scope) {
  2338 + this.core = scope;
  2339 + this.core.options = $.extend({}, Animate.Defaults, this.core.options);
  2340 + this.swapping = true;
  2341 + this.previous = undefined;
  2342 + this.next = undefined;
  2343 +
  2344 + this.handlers = {
  2345 + 'change.owl.carousel': $.proxy(function(e) {
  2346 + if (e.property.name == 'position') {
  2347 + this.previous = this.core.current();
  2348 + this.next = e.property.value;
  2349 + }
  2350 + }, this),
  2351 + 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
  2352 + this.swapping = e.type == 'translated';
  2353 + }, this),
  2354 + 'translate.owl.carousel': $.proxy(function(e) {
  2355 + if (this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
  2356 + this.swap();
  2357 + }
  2358 + }, this)
  2359 + };
  2360 +
  2361 + this.core.$element.on(this.handlers);
  2362 + };
  2363 +
  2364 + /**
  2365 + * Default options.
  2366 + * @public
  2367 + */
  2368 + Animate.Defaults = {
  2369 + animateOut: false,
  2370 + animateIn: false
  2371 + };
  2372 +
  2373 + /**
  2374 + * Toggles the animation classes whenever an translations starts.
  2375 + * @protected
  2376 + * @returns {Boolean|undefined}
  2377 + */
  2378 + Animate.prototype.swap = function() {
  2379 +
  2380 + if (this.core.settings.items !== 1 || !this.core.support3d) {
  2381 + return;
  2382 + }
  2383 +
  2384 + this.core.speed(0);
  2385 +
  2386 + var left,
  2387 + clear = $.proxy(this.clear, this),
  2388 + previous = this.core.$stage.children().eq(this.previous),
  2389 + next = this.core.$stage.children().eq(this.next),
  2390 + incoming = this.core.settings.animateIn,
  2391 + outgoing = this.core.settings.animateOut;
  2392 +
  2393 + if (this.core.current() === this.previous) {
  2394 + return;
  2395 + }
  2396 +
  2397 + if (outgoing) {
  2398 + left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
  2399 + previous.css( { 'left': left + 'px' } )
  2400 + .addClass('animated owl-animated-out')
  2401 + .addClass(outgoing)
  2402 + .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', clear);
  2403 + }
  2404 +
  2405 + if (incoming) {
  2406 + next.addClass('animated owl-animated-in')
  2407 + .addClass(incoming)
  2408 + .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', clear);
  2409 + }
  2410 + };
  2411 +
  2412 + Animate.prototype.clear = function(e) {
  2413 + $(e.target).css( { 'left': '' } )
  2414 + .removeClass('animated owl-animated-out owl-animated-in')
  2415 + .removeClass(this.core.settings.animateIn)
  2416 + .removeClass(this.core.settings.animateOut);
  2417 + this.core.transitionEnd();
  2418 + }
  2419 +
  2420 + /**
  2421 + * Destroys the plugin.
  2422 + * @public
  2423 + */
  2424 + Animate.prototype.destroy = function() {
  2425 + var handler, property;
  2426 +
  2427 + for (handler in this.handlers) {
  2428 + this.core.$element.off(handler, this.handlers[handler]);
  2429 + }
  2430 + for (property in Object.getOwnPropertyNames(this)) {
  2431 + typeof this[property] != 'function' && (this[property] = null);
  2432 + }
  2433 + };
  2434 +
  2435 + $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
  2436 +
  2437 +})(window.Zepto || window.jQuery, window, document);
  2438 +
  2439 +/**
  2440 + * Autoplay Plugin
  2441 + * @version 2.0.0
  2442 + * @author Bartosz Wojciechowski
  2443 + * @license The MIT License (MIT)
  2444 + */
  2445 +;(function($, window, document, undefined) {
  2446 +
  2447 + /**
  2448 + * Creates the autoplay plugin.
  2449 + * @class The Autoplay Plugin
  2450 + * @param {Owl} scope - The Owl Carousel
  2451 + */
  2452 + var Autoplay = function(scope) {
  2453 + this.core = scope;
  2454 + this.core.options = $.extend({}, Autoplay.Defaults, this.core.options);
  2455 +
  2456 + this.handlers = {
  2457 + 'translated.owl.carousel refreshed.owl.carousel': $.proxy(function() {
  2458 + this.autoplay();
  2459 + }, this),
  2460 + 'play.owl.autoplay': $.proxy(function(e, t, s) {
  2461 + this.play(t, s);
  2462 + }, this),
  2463 + 'stop.owl.autoplay': $.proxy(function() {
  2464 + this.stop();
  2465 + }, this),
  2466 + 'mouseover.owl.autoplay': $.proxy(function() {
  2467 + if (this.core.settings.autoplayHoverPause) {
  2468 + this.pause();
  2469 + }
  2470 + }, this),
  2471 + 'mouseleave.owl.autoplay': $.proxy(function() {
  2472 + if (this.core.settings.autoplayHoverPause) {
  2473 + this.autoplay();
  2474 + }
  2475 + }, this)
  2476 + };
  2477 +
  2478 + this.core.$element.on(this.handlers);
  2479 + };
  2480 +
  2481 + /**
  2482 + * Default options.
  2483 + * @public
  2484 + */
  2485 + Autoplay.Defaults = {
  2486 + autoplay: false,
  2487 + autoplayTimeout: 5000,
  2488 + autoplayHoverPause: false,
  2489 + autoplaySpeed: false
  2490 + };
  2491 +
  2492 + /**
  2493 + * @protected
  2494 + * @todo Must be documented.
  2495 + */
  2496 + Autoplay.prototype.autoplay = function() {
  2497 + if (this.core.settings.autoplay && !this.core.state.videoPlay) {
  2498 + window.clearInterval(this.interval);
  2499 +
  2500 + this.interval = window.setInterval($.proxy(function() {
  2501 + this.play();
  2502 + }, this), this.core.settings.autoplayTimeout);
  2503 + } else {
  2504 + window.clearInterval(this.interval);
  2505 + }
  2506 + };
  2507 +
  2508 + /**
  2509 + * Starts the autoplay.
  2510 + * @public
  2511 + * @param {Number} [timeout] - ...
  2512 + * @param {Number} [speed] - ...
  2513 + * @returns {Boolean|undefined} - ...
  2514 + * @todo Must be documented.
  2515 + */
  2516 + Autoplay.prototype.play = function(timeout, speed) {
  2517 + // if tab is inactive - doesnt work in <IE10
  2518 + if (document.hidden === true) {
  2519 + return;
  2520 + }
  2521 +
  2522 + if (this.core.state.isTouch || this.core.state.isScrolling
  2523 + || this.core.state.isSwiping || this.core.state.inMotion) {
  2524 + return;
  2525 + }
  2526 +
  2527 + if (this.core.settings.autoplay === false) {
  2528 + window.clearInterval(this.interval);
  2529 + return;
  2530 + }
  2531 +
  2532 + this.core.next(this.core.settings.autoplaySpeed);
  2533 + };
  2534 +
  2535 + /**
  2536 + * Stops the autoplay.
  2537 + * @public
  2538 + */
  2539 + Autoplay.prototype.stop = function() {
  2540 + window.clearInterval(this.interval);
  2541 + };
  2542 +
  2543 + /**
  2544 + * Pauses the autoplay.
  2545 + * @public
  2546 + */
  2547 + Autoplay.prototype.pause = function() {
  2548 + window.clearInterval(this.interval);
  2549 + };
  2550 +
  2551 + /**
  2552 + * Destroys the plugin.
  2553 + */
  2554 + Autoplay.prototype.destroy = function() {
  2555 + var handler, property;
  2556 +
  2557 + window.clearInterval(this.interval);
  2558 +
  2559 + for (handler in this.handlers) {
  2560 + this.core.$element.off(handler, this.handlers[handler]);
  2561 + }
  2562 + for (property in Object.getOwnPropertyNames(this)) {
  2563 + typeof this[property] != 'function' && (this[property] = null);
  2564 + }
  2565 + };
  2566 +
  2567 + $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
  2568 +
  2569 +})(window.Zepto || window.jQuery, window, document);
  2570 +
  2571 +/**
  2572 + * Navigation Plugin
  2573 + * @version 2.0.0
  2574 + * @author Artus Kolanowski
  2575 + * @license The MIT License (MIT)
  2576 + */
  2577 +;(function($, window, document, undefined) {
  2578 + 'use strict';
  2579 +
  2580 + /**
  2581 + * Creates the navigation plugin.
  2582 + * @class The Navigation Plugin
  2583 + * @param {Owl} carousel - The Owl Carousel.
  2584 + */
  2585 + var Navigation = function(carousel) {
  2586 + /**
  2587 + * Reference to the core.
  2588 + * @protected
  2589 + * @type {Owl}
  2590 + */
  2591 + this._core = carousel;
  2592 +
  2593 + /**
  2594 + * Indicates whether the plugin is initialized or not.
  2595 + * @protected
  2596 + * @type {Boolean}
  2597 + */
  2598 + this._initialized = false;
  2599 +
  2600 + /**
  2601 + * The current paging indexes.
  2602 + * @protected
  2603 + * @type {Array}
  2604 + */
  2605 + this._pages = [];
  2606 +
  2607 + /**
  2608 + * All DOM elements of the user interface.
  2609 + * @protected
  2610 + * @type {Object}
  2611 + */
  2612 + this._controls = {};
  2613 +
  2614 + /**
  2615 + * Markup for an indicator.
  2616 + * @protected
  2617 + * @type {Array.<String>}
  2618 + */
  2619 + this._templates = [];
  2620 +
  2621 + /**
  2622 + * The carousel element.
  2623 + * @type {jQuery}
  2624 + */
  2625 + this.$element = this._core.$element;
  2626 +
  2627 + /**
  2628 + * Overridden methods of the carousel.
  2629 + * @protected
  2630 + * @type {Object}
  2631 + */
  2632 + this._overrides = {
  2633 + next: this._core.next,
  2634 + prev: this._core.prev,
  2635 + to: this._core.to
  2636 + };
  2637 +
  2638 + /**
  2639 + * All event handlers.
  2640 + * @protected
  2641 + * @type {Object}
  2642 + */
  2643 + this._handlers = {
  2644 + 'prepared.owl.carousel': $.proxy(function(e) {
  2645 + if (this._core.settings.dotsData) {
  2646 + this._templates.push($(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot'));
  2647 + }
  2648 + }, this),
  2649 + 'add.owl.carousel': $.proxy(function(e) {
  2650 + if (this._core.settings.dotsData) {
  2651 + this._templates.splice(e.position, 0, $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot'));
  2652 + }
  2653 + }, this),
  2654 + 'remove.owl.carousel prepared.owl.carousel': $.proxy(function(e) {
  2655 + if (this._core.settings.dotsData) {
  2656 + this._templates.splice(e.position, 1);
  2657 + }
  2658 + }, this),
  2659 + 'change.owl.carousel': $.proxy(function(e) {
  2660 + if (e.property.name == 'position') {
  2661 + if (!this._core.state.revert && !this._core.settings.loop && this._core.settings.navRewind) {
  2662 + var current = this._core.current(),
  2663 + maximum = this._core.maximum(),
  2664 + minimum = this._core.minimum();
  2665 + e.data = e.property.value > maximum
  2666 + ? current >= maximum ? minimum : maximum
  2667 + : e.property.value < minimum ? maximum : e.property.value;
  2668 + }
  2669 + }
  2670 + }, this),
  2671 + 'changed.owl.carousel': $.proxy(function(e) {
  2672 + if (e.property.name == 'position') {
  2673 + this.draw();
  2674 + }
  2675 + }, this),
  2676 + 'refreshed.owl.carousel': $.proxy(function() {
  2677 + if (!this._initialized) {
  2678 + this.initialize();
  2679 + this._initialized = true;
  2680 + }
  2681 + this._core.trigger('refresh', null, 'navigation');
  2682 + this.update();
  2683 + this.draw();
  2684 + this._core.trigger('refreshed', null, 'navigation');
  2685 + }, this)
  2686 + };
  2687 +
  2688 + // set default options
  2689 + this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
  2690 +
  2691 + // register event handlers
  2692 + this.$element.on(this._handlers);
  2693 + }
  2694 +
  2695 + /**
  2696 + * Default options.
  2697 + * @public
  2698 + * @todo Rename `slideBy` to `navBy`
  2699 + */
  2700 + Navigation.Defaults = {
  2701 + nav: false,
  2702 + navRewind: true,
  2703 + navText: [ 'prev', 'next' ],
  2704 + navSpeed: false,
  2705 + navElement: 'div',
  2706 + navContainer: false,
  2707 + navContainerClass: 'owl-nav',
  2708 + navClass: [ 'owl-prev', 'owl-next' ],
  2709 + slideBy: 1,
  2710 + dotClass: 'owl-dot',
  2711 + dotsClass: 'owl-dots',
  2712 + dots: true,
  2713 + dotsEach: false,
  2714 + dotData: false,
  2715 + dotsSpeed: false,
  2716 + dotsContainer: false,
  2717 + controlsClass: 'owl-controls'
  2718 + }
  2719 +
  2720 + /**
  2721 + * Initializes the layout of the plugin and extends the carousel.
  2722 + * @protected
  2723 + */
  2724 + Navigation.prototype.initialize = function() {
  2725 + var $container, override,
  2726 + options = this._core.settings;
  2727 +
  2728 + // create the indicator template
  2729 + if (!options.dotsData) {
  2730 + this._templates = [ $('<div>')
  2731 + .addClass(options.dotClass)
  2732 + .append($('<span>'))
  2733 + .prop('outerHTML') ];
  2734 + }
  2735 +
  2736 + // create controls container if needed
  2737 + if (!options.navContainer || !options.dotsContainer) {
  2738 + this._controls.$container = $('<div>')
  2739 + .addClass(options.controlsClass)
  2740 + .appendTo(this.$element);
  2741 + }
  2742 +
  2743 + // create DOM structure for absolute navigation
  2744 + this._controls.$indicators = options.dotsContainer ? $(options.dotsContainer)
  2745 + : $('<div>').hide().addClass(options.dotsClass).appendTo(this._controls.$container);
  2746 +
  2747 + this._controls.$indicators.on('click', 'div', $.proxy(function(e) {
  2748 + var index = $(e.target).parent().is(this._controls.$indicators)
  2749 + ? $(e.target).index() : $(e.target).parent().index();
  2750 +
  2751 + e.preventDefault();
  2752 +
  2753 + this.to(index, options.dotsSpeed);
  2754 + }, this));
  2755 +
  2756 + // create DOM structure for relative navigation
  2757 + $container = options.navContainer ? $(options.navContainer)
  2758 + : $('<div>').addClass(options.navContainerClass).prependTo(this._controls.$container);
  2759 +
  2760 + this._controls.$next = $('<' + options.navElement + '>');
  2761 + this._controls.$previous = this._controls.$next.clone();
  2762 +
  2763 + this._controls.$previous
  2764 + .addClass(options.navClass[0])
  2765 + .html(options.navText[0])
  2766 + .hide()
  2767 + .prependTo($container)
  2768 + .on('click', $.proxy(function(e) {
  2769 + this.prev(options.navSpeed);
  2770 + }, this));
  2771 + this._controls.$next
  2772 + .addClass(options.navClass[1])
  2773 + .html(options.navText[1])
  2774 + .hide()
  2775 + .appendTo($container)
  2776 + .on('click', $.proxy(function(e) {
  2777 + this.next(options.navSpeed);
  2778 + }, this));
  2779 +
  2780 + // override public methods of the carousel
  2781 + for (override in this._overrides) {
  2782 + this._core[override] = $.proxy(this[override], this);
  2783 + }
  2784 + }
  2785 +
  2786 + /**
  2787 + * Destroys the plugin.
  2788 + * @protected
  2789 + */
  2790 + Navigation.prototype.destroy = function() {
  2791 + var handler, control, property, override;
  2792 +
  2793 + for (handler in this._handlers) {
  2794 + this.$element.off(handler, this._handlers[handler]);
  2795 + }
  2796 + for (control in this._controls) {
  2797 + this._controls[control].remove();
  2798 + }
  2799 + for (override in this.overides) {
  2800 + this._core[override] = this._overrides[override];
  2801 + }
  2802 + for (property in Object.getOwnPropertyNames(this)) {
  2803 + typeof this[property] != 'function' && (this[property] = null);
  2804 + }
  2805 + }
  2806 +
  2807 + /**
  2808 + * Updates the internal state.
  2809 + * @protected
  2810 + */
  2811 + Navigation.prototype.update = function() {
  2812 + var i, j, k,
  2813 + options = this._core.settings,
  2814 + lower = this._core.clones().length / 2,
  2815 + upper = lower + this._core.items().length,
  2816 + size = options.center || options.autoWidth || options.dotData
  2817 + ? 1 : options.dotsEach || options.items;
  2818 +
  2819 + if (options.slideBy !== 'page') {
  2820 + options.slideBy = Math.min(options.slideBy, options.items);
  2821 + }
  2822 +
  2823 + if (options.dots || options.slideBy == 'page') {
  2824 + this._pages = [];
  2825 +
  2826 + for (i = lower, j = 0, k = 0; i < upper; i++) {
  2827 + if (j >= size || j === 0) {
  2828 + this._pages.push({
  2829 + start: i - lower,
  2830 + end: i - lower + size - 1
  2831 + });
  2832 + j = 0, ++k;
  2833 + }
  2834 + j += this._core.mergers(this._core.relative(i));
  2835 + }
  2836 + }
  2837 + }
  2838 +
  2839 + /**
  2840 + * Draws the user interface.
  2841 + * @todo The option `dotData` wont work.
  2842 + * @protected
  2843 + */
  2844 + Navigation.prototype.draw = function() {
  2845 + var difference, i, html = '',
  2846 + options = this._core.settings,
  2847 + $items = this._core.$stage.children(),
  2848 + index = this._core.relative(this._core.current());
  2849 +
  2850 + if (options.nav && !options.loop && !options.navRewind) {
  2851 + this._controls.$previous.toggleClass('disabled', index <= 0);
  2852 + this._controls.$next.toggleClass('disabled', index >= this._core.maximum());
  2853 + }
  2854 +
  2855 + this._controls.$previous.toggle(options.nav);
  2856 + this._controls.$next.toggle(options.nav);
  2857 +
  2858 + if (options.dots) {
  2859 + difference = this._pages.length - this._controls.$indicators.children().length;
  2860 +
  2861 + if (options.dotData && difference !== 0) {
  2862 + for (i = 0; i < this._controls.$indicators.children().length; i++) {
  2863 + html += this._templates[this._core.relative(i)];
  2864 + }
  2865 + this._controls.$indicators.html(html);
  2866 + } else if (difference > 0) {
  2867 + html = new Array(difference + 1).join(this._templates[0]);
  2868 + this._controls.$indicators.append(html);
  2869 + } else if (difference < 0) {
  2870 + this._controls.$indicators.children().slice(difference).remove();
  2871 + }
  2872 +
  2873 + this._controls.$indicators.find('.active').removeClass('active');
  2874 + this._controls.$indicators.children().eq($.inArray(this.current(), this._pages)).addClass('active');
  2875 + }
  2876 +
  2877 + this._controls.$indicators.toggle(options.dots);
  2878 + }
  2879 +
  2880 + /**
  2881 + * Extends event data.
  2882 + * @protected
  2883 + * @param {Event} event - The event object which gets thrown.
  2884 + */
  2885 + Navigation.prototype.onTrigger = function(event) {
  2886 + var settings = this._core.settings;
  2887 +
  2888 + event.page = {
  2889 + index: $.inArray(this.current(), this._pages),
  2890 + count: this._pages.length,
  2891 + size: settings && (settings.center || settings.autoWidth || settings.dotData
  2892 + ? 1 : settings.dotsEach || settings.items)
  2893 + };
  2894 + }
  2895 +
  2896 + /**
  2897 + * Gets the current page position of the carousel.
  2898 + * @protected
  2899 + * @returns {Number}
  2900 + */
  2901 + Navigation.prototype.current = function() {
  2902 + var index = this._core.relative(this._core.current());
  2903 + return $.grep(this._pages, function(o) {
  2904 + return o.start <= index && o.end >= index;
  2905 + }).pop();
  2906 + }
  2907 +
  2908 + /**
  2909 + * Gets the current succesor/predecessor position.
  2910 + * @protected
  2911 + * @returns {Number}
  2912 + */
  2913 + Navigation.prototype.getPosition = function(successor) {
  2914 + var position, length,
  2915 + options = this._core.settings;
  2916 +
  2917 + if (options.slideBy == 'page') {
  2918 + position = $.inArray(this.current(), this._pages);
  2919 + length = this._pages.length;
  2920 + successor ? ++position : --position;
  2921 + position = this._pages[((position % length) + length) % length].start;
  2922 + } else {
  2923 + position = this._core.relative(this._core.current());
  2924 + length = this._core.items().length;
  2925 + successor ? position += options.slideBy : position -= options.slideBy;
  2926 + }
  2927 + return position;
  2928 + }
  2929 +
  2930 + /**
  2931 + * Slides to the next item or page.
  2932 + * @public
  2933 + * @param {Number} [speed=false] - The time in milliseconds for the transition.
  2934 + */
  2935 + Navigation.prototype.next = function(speed) {
  2936 + $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
  2937 + }
  2938 +
  2939 + /**
  2940 + * Slides to the previous item or page.
  2941 + * @public
  2942 + * @param {Number} [speed=false] - The time in milliseconds for the transition.
  2943 + */
  2944 + Navigation.prototype.prev = function(speed) {
  2945 + $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
  2946 + }
  2947 +
  2948 + /**
  2949 + * Slides to the specified item or page.
  2950 + * @public
  2951 + * @param {Number} position - The position of the item or page.
  2952 + * @param {Number} [speed] - The time in milliseconds for the transition.
  2953 + * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
  2954 + */
  2955 + Navigation.prototype.to = function(position, speed, standard) {
  2956 + var length;
  2957 +
  2958 + if (!standard) {
  2959 + length = this._pages.length;
  2960 + $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
  2961 + } else {
  2962 + $.proxy(this._overrides.to, this._core)(position, speed);
  2963 + }
  2964 + }
  2965 +
  2966 + $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
  2967 +
  2968 +})(window.Zepto || window.jQuery, window, document);
  2969 +
  2970 +/**
  2971 + * Hash Plugin
  2972 + * @version 2.0.0
  2973 + * @author Artus Kolanowski
  2974 + * @license The MIT License (MIT)
  2975 + */
  2976 +;(function($, window, document, undefined) {
  2977 + 'use strict';
  2978 +
  2979 + /**
  2980 + * Creates the hash plugin.
  2981 + * @class The Hash Plugin
  2982 + * @param {Owl} carousel - The Owl Carousel
  2983 + */
  2984 + var Hash = function(carousel) {
  2985 + /**
  2986 + * Reference to the core.
  2987 + * @protected
  2988 + * @type {Owl}
  2989 + */
  2990 + this._core = carousel;
  2991 +
  2992 + /**
  2993 + * Hash table for the hashes.
  2994 + * @protected
  2995 + * @type {Object}
  2996 + */
  2997 + this._hashes = {};
  2998 +
  2999 + /**
  3000 + * The carousel element.
  3001 + * @type {jQuery}
  3002 + */
  3003 + this.$element = this._core.$element;
  3004 +
  3005 + /**
  3006 + * All event handlers.
  3007 + * @protected
  3008 + * @type {Object}
  3009 + */
  3010 + this._handlers = {
  3011 + 'initialized.owl.carousel': $.proxy(function() {
  3012 + if (this._core.settings.startPosition == 'URLHash') {
  3013 + $(window).trigger('hashchange.owl.navigation');
  3014 + }
  3015 + }, this),
  3016 + 'prepared.owl.carousel': $.proxy(function(e) {
  3017 + var hash = $(e.content).find('[data-hash]').andSelf('[data-hash]').attr('data-hash');
  3018 + this._hashes[hash] = e.content;
  3019 + }, this)
  3020 + };
  3021 +
  3022 + // set default options
  3023 + this._core.options = $.extend({}, Hash.Defaults, this._core.options);
  3024 +
  3025 + // register the event handlers
  3026 + this.$element.on(this._handlers);
  3027 +
  3028 + // register event listener for hash navigation
  3029 + $(window).on('hashchange.owl.navigation', $.proxy(function() {
  3030 + var hash = window.location.hash.substring(1),
  3031 + items = this._core.$stage.children(),
  3032 + position = this._hashes[hash] && items.index(this._hashes[hash]) || 0;
  3033 +
  3034 + if (!hash) {
  3035 + return false;
  3036 + }
  3037 +
  3038 + this._core.to(position, false, true);
  3039 + }, this));
  3040 + }
  3041 +
  3042 + /**
  3043 + * Default options.
  3044 + * @public
  3045 + */
  3046 + Hash.Defaults = {
  3047 + URLhashListener: false
  3048 + }
  3049 +
  3050 + /**
  3051 + * Destroys the plugin.
  3052 + * @public
  3053 + */
  3054 + Hash.prototype.destroy = function() {
  3055 + var handler, property;
  3056 +
  3057 + $(window).off('hashchange.owl.navigation');
  3058 +
  3059 + for (handler in this._handlers) {
  3060 + this._core.$element.off(handler, this._handlers[handler]);
  3061 + }
  3062 + for (property in Object.getOwnPropertyNames(this)) {
  3063 + typeof this[property] != 'function' && (this[property] = null);
  3064 + }
  3065 + }
  3066 +
  3067 + $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
  3068 +
  3069 +})(window.Zepto || window.jQuery, window, document);
... ...
frontend/widgets/Slider.php
... ... @@ -19,10 +19,13 @@ class Slider extends Widget
19 19  
20 20  
21 21 $slider = \common\models\Slider::find()->where([\common\models\Slider::tableName().'.title'=>$this->title])->joinWith("sliderImage")->one();
  22 + if($slider instanceof \common\models\Slider){
  23 + return $this->render('slider',[
  24 + 'slider'=>$slider,
  25 + 'title'=>$this->title
  26 + ]);
22 27  
23   - return $this->render('slider',[
24   - 'slider'=>$slider
25   - ]);
  28 + }
26 29  
27 30  
28 31 }
... ...
frontend/widgets/views/slider.php
1 1 <?php
2 2 /* @var $slider Slider*/
  3 +use common\components\artboximage\ArtboxImageHelper;
3 4 use common\models\Slider;
4 5 use yii\helpers\Html;
5 6 use yii\helpers\Url;
  7 +use yii\web\View;
6 8  
7 9 ?>
8   -<div class="carousel">
  10 +
  11 +
  12 +<div id="<?=$title?>" class="owl-carousel owl-theme">
9 13 <?php foreach($slider->sliderImage as $image):
10   - $htm = <<<HTML
11   -
12   - <div style="background:url($image->image ) center center no-repeat;width:100%;height:480px;position:absolute;">
13   - </div>
14   - <div class="content">
15   -
16   -HTML;
17   -
18   - if(!empty($image->price)) {
19   - $htm .= <<<HTML
20   - <div class="price_round_border">
21   - <div class="price_round">
22   - <div class="title">Супер цена</div>
23   - <div class="desc">$image->price
24   - <div>грн.</div>
25   - </div>
26   - </div>
27   - </div>
28   -HTML;
29   - }
30   -
31   - $htm .= <<<HTML
32   - </div>
33   -
34   -HTML;
35   - ?>
36   -
37   - <div class="slide">
38   - <?= Html::a($htm, Url::toRoute($image->url)); ?>
  14 +
  15 +
  16 + ?>
  17 + <div class="item">
  18 + <?= Html::img(ArtboxImageHelper::getImageSrc($image->imageUrl,'slider'))?>
39 19 </div>
  20 +
  21 +
  22 +
40 23 <?php endforeach; ?>
41 24 </div>
42   -
43   -<div style="clear:both;"></div>
44 25 <?php
45 26 $dur = $slider->duration ? $slider->duration : 5000;
46 27 $speed = $slider->speed ? $slider->speed : 500;
47   -$js=" $(\".carousel\").owlCarousel({
48   - items: 1,
49   - loop: true,
50   - nav: true,
51   - startPosition: 2,
52   - mouseDrag: false,
53   - navSpeed: 800,
54   - autoplay:true,
55   - autoplayTimeout: $dur,
56   - autoplaySpeed: $speed,
57   - autoplayHoverPause:true,
58   - navText: ['<a class=\"prev\"></a>', '<a class=\"next\"></a>']
  28 +$js=" $(\"#$title\").owlCarousel({
  29 + navigation : true, // Show next and prev buttons
  30 + slideSpeed : 300,
  31 + paginationSpeed : 400,
  32 + singleItem:true
  33 +
59 34 });";
60 35  
61   -$this->registerJs($js);
  36 +$this->registerJs($js,View::POS_END);
62 37  
63 38 ?>
... ...