diff --git a/app/Classes/RusDate.php b/app/Classes/RusDate.php index 5af75c6..0f30a59 100644 --- a/app/Classes/RusDate.php +++ b/app/Classes/RusDate.php @@ -4,6 +4,8 @@ namespace App\Classes; +use DateTime; + class RusDate { public static function russian_date($date = null){ @@ -72,4 +74,46 @@ class RusDate unset($_COOKIE['favorite_house']); //print_r($_COOKIE['arr']); } + + public static function interval_month($date) { + $now = new DateTime(); + $date = new DateTime($date); //::createFromFormat("Y-m-d H:i", $date); + $interval = $now->diff($date); + $y = $interval->y; + $d = $interval->d; + $h = $interval->h; + $i = $interval->i; + + if ($d > 30) + return true; + else + return false; + } + + public static function interval_day($date) { + $now = new DateTime(); + $date = new DateTime($date); //::createFromFormat("Y-m-d H:i", $date); + $interval = $now->diff($date); + $y = $interval->y; + $d = $interval->d; + $h = $interval->h; + $i = $interval->i; + + if (($h > 24) || ($d > 0) || ($y > 0)) + return true; + else + return false; + } + + public static function ip_addr_client() { + $client = @$_SERVER['HTTP_CLIENT_IP']; + $forward = @$_SERVER['HTTP_X_FORWARDED_FOR']; + $remote = @$_SERVER['REMOTE_ADDR']; + + if(filter_var($client, FILTER_VALIDATE_IP)) $ip = $client; + elseif(filter_var($forward, FILTER_VALIDATE_IP)) $ip = $forward; + else $ip = $remote; + + return $ip; + } } diff --git a/app/Http/Controllers/MainController.php b/app/Http/Controllers/MainController.php index 83efe80..931149a 100644 --- a/app/Http/Controllers/MainController.php +++ b/app/Http/Controllers/MainController.php @@ -10,11 +10,13 @@ use App\Models\format_area; use App\Models\House; use App\Models\ModelMailFeedback; use App\Models\News; +use App\Models\Page; use App\Models\Partners; use App\Models\type_area; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; use App\Classes\RusDate; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Mail; use PhpParser\Node\Stmt\Switch_; use Illuminate\Support\Facades\Response; @@ -732,13 +734,46 @@ class MainController extends Controller /* * Посмотр конктретного предложение офиса */ - public function Offer(House $house) { + public function Offer(House $house, Request $request) { $houses = House::with('areas'); $houses = $houses->where('type_area_id', '=', $house->typearea->id); $houses = $houses->where('format_house', '=', $house->format_house); $houses = $houses->orderByDesc('created_at')->limit(8)->get(); - return view('house.post', compact('house', 'houses')); + //получение адреса страницы + $url = $request->url(); + // получение ip-адреса клиента + $ip = RusDate::ip_addr_client(); + + //получение выборки данных из базы данных по данной странице + $page_ = Page::query()->where('url', '=', "$url")-> + orderBy('created_at')->limit(1)->get(); + + //если интервал времени больше суток, то обнуляем счетчик + if ($page_->count()) { + $result = RusDate::interval_day($page_[0]->created_at); + if ($result) { + DB::table('pages')->where('url', '=', "$url")->delete(); + } + } + // проверяем если в базе данных данный ip-адрес + $count_user = DB::table('pages')->where('ipaddress', '=', "$ip")-> + where('url', '=', "$url")->get(); + // если есть, то обновляем дату просмотра + if ($count_user->count() > 0) { + DB::table('pages')->where('ipaddress', '=', "$ip")-> + where('url', '=', "$url")->update(['created_at' => date('Y-m-d H:i')]); + } else { + // в противном случае добавляем новый ip В бд + $page = new Page(); + $page->ipaddress = $ip; + $page->url = $url; + $page->save(); + } + + // выводим количество пользователей гостей данной страницы + $count_user = DB::table('pages')->where('url', '=', "$url")->get(); + return view('house.post', compact('house', 'houses', 'count_user')); } /* diff --git a/app/Models/Page.php b/app/Models/Page.php new file mode 100644 index 0000000..3efdf5b --- /dev/null +++ b/app/Models/Page.php @@ -0,0 +1,11 @@ +id(); + $table->string('ipaddress', 100); + $table->string('url', 255); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('pages'); + } +}; diff --git a/public/js/main_main.js b/public/js/main_main.js new file mode 100644 index 0000000..629c2b1 --- /dev/null +++ b/public/js/main_main.js @@ -0,0 +1,1508 @@ +// управляющий класс App с методом init(), в котором собраны все используемые методы с комментариями о том, что конкретно делает каждый метод + +class App { + + constructor() { + this.patternPhone = /^(\+7|7|8)?[\s\-]?\(?[489][0-9]{2}\)?[\s\-]?[0-9]{3}[\s\-]?[0-9]{2}[\s\-]?[0-9]{2}$/; // рег. выражение для поля 'телефон'; + this.patternEmail = /^[a-zA-Z0-9._%+-\.]+@[a-z0-9.-]+\.[a-z]{2,}$/i; // рег. выражение для поля 'электронная почта'; + } + + init() { + + console.log('init'); + + this.stickyHeader(); // липкий хедер; + this.controlBurgerMenu(); // бургер-меню; + this.smoothScroll(); // плавный скролл к якорю (smooth scroll); + this.scrollUp(); // кнопка наверх; + this.addToFavorites(); // добавить в избранное (звёздочка); + this.initTypicalSlider(); // типовые слайдеры; + this.initPartnerslSlider(); // слайдер с партнёрами; + this.controlFilters(); // фильтры на главном экране; + this.controlPopups(); // открытие/закрытие поп-апов; + this.controlContactUsPopup(); // открытие/закрытие поп-апа 'обратный звонок'; + + this.sendForm('.js_popup_feedback_form', '[data-popup="success"]'); // отправка формы в поп-апе обратной связи; + this.sendForm('.js_popup_viewing_form', '[data-popup="success"]'); // отправка формы в поп-апе 'записаться на просмотр'; + this.sendForm('.js_footer_feedback_form', '[data-popup="success"]'); // отправка формы в футере; + this.sendForm('.js_contacts_form', '.js_contacts_success'); // отправка формы на странице контакты; + this.sendForm('.js_popup_sending_form_', '[data-popup="success"]'); + //this.sendOffer(); //отправка предложения по e-mail; + + //this.setGeneralMap(); // карта на странице карт; + //this.setComplexMap('complex-map', [55.726591050908745, 37.57244549999999], 'ЖК Садовые кварталы'); // карта на странице 'ЖК'; + //this.setComplexMap('offer-map', [55.70851106903402, 37.65864349999999], 'Аренда торгового помещения 321,6 м2'); // карта на странице 'Предложение'; + this.setCatalogSorts(); // сортировка на странице 'каталог'; + this.initIntroSlider(); // слайдер на странице жк и на странице предложения; + this.setTabs('.js_offer_side_tab', '.js_offer_side_item'); // табы с планами объекат и этажа на странице предложения; + this.setTabs('.js_offer_side_popup_tab', '.js_offer_side_popup_item'); // табы с планами объекат и этажа в поп-апе на странице предложения; + this.sontrolOfferSidePopup(); // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения; + this.setCustomGallery(); // галлерея; + this.setCookies() // куки; + this.setFooterSpoilers() // аккордеон в футере; + + } + + // фиксация + fixBodyPosition() { + + setTimeout(function () { + // ставим необходимую задержку, чтобы не было «конфликта» в случае, если функция фиксации вызывается сразу после расфиксации (расфиксация отменяет действия расфиксации из-за одновременного действия) + + if (!document.body.hasAttribute('data-body-scroll-fix')) { + + // получаем позицию прокрутки + let scrollPosition = window.pageYOffset || document.documentElement.scrollTop; + + // ставим нужные стили + document.body.setAttribute('data-body-scroll-fix', scrollPosition); // Cтавим атрибут со значением прокрутки + document.body.style.overflow = 'hidden'; + document.body.style.position = 'fixed'; + document.body.style.top = '-' + scrollPosition + 'px'; + document.body.style.left = '0'; + document.body.style.width = '100%'; + + if (window.innerWidth >= 1200) { + document.body.style.paddingRight = '8px'; + } + } + + }, 15); // можно задержку ещё меньше, но работает хорошо именно с этим значением на всех устройствах и браузерах + + } + + + // расфиксация + unfixBodyPosition() { + + if (document.body.hasAttribute('data-body-scroll-fix')) { + + // получаем позицию прокрутки из атрибута + let scrollPosition = document.body.getAttribute('data-body-scroll-fix'); + + // удаляем атрибут + document.body.removeAttribute('data-body-scroll-fix'); + + // удаляем ненужные стили + document.body.style.overflow = ''; + document.body.style.position = ''; + document.body.style.top = ''; + document.body.style.left = ''; + document.body.style.width = ''; + document.body.style.paddingRight = ''; + + // прокручиваем страницу на полученное из атрибута значение + window.scroll(0, scrollPosition); + + } + + } + + + // бургер-меню + controlBurgerMenu() { + + const headerBurger = document.querySelector('.js_header_burger'); + + if (headerBurger) { + + const menu = document.querySelector('.js_menu'); + const menuClose = menu.querySelector('.js_menu_close'); + + headerBurger.addEventListener('click', () => { + menu.classList.add('active'); + this.fixBodyPosition(); + }); + + menu.addEventListener('click', (e) => { + + if (e.target == menu) { + menu.classList.remove('active'); + this.unfixBodyPosition(); + } + + }); + + menuClose.addEventListener('click', () => { + menu.classList.remove('active'); + this.unfixBodyPosition(); + }); + + } + + } + + + // липкий хедер + stickyHeader() { + + const header = document.querySelector('.js_header'); + + if (header) { + + window.addEventListener('scroll', () => { + + if (window.scrollY > 200) { + header.classList.add('fixed'); + } else { + header.classList.remove('fixed'); + } + + }); + + }; + + } + + + // плавный скролл к якорю (smooth scroll) + smoothScroll() { + + const smoothLinks = document.querySelectorAll('.js_smooth_link'); + + if (smoothLinks.length) { + + smoothLinks.forEach(link => { + + link.addEventListener('click', function (e) { + + e.preventDefault(); + + let href = this.getAttribute('href').substring(1); + + const scrollTarget = document.getElementById(href); + + // const topOffset = document.querySelector('.header').offsetHeight; + const topOffset = 0; // если не нужен отступ сверху + const elementPosition = scrollTarget.getBoundingClientRect().top; + const offsetPosition = elementPosition - topOffset; + + window.scrollBy({ + top: offsetPosition, + behavior: 'smooth' + }); + + }); + + }); + + } + + } + + + // кнопка наверх + scrollUp() { + + const toTopBtn = document.querySelector('.js_btn_up'); + + if (toTopBtn) { + + toTopBtn.addEventListener('click', function () { + + window.scrollTo({ + top: 0, + behavior: 'smooth' + }); + + }); + + } + + } + + + // добавить в избранное (звёздочка) + addToFavorites() { + + const cardFavorites = document.querySelectorAll('.js_card_favorites'); + + if (cardFavorites.length) { + + cardFavorites.forEach(item => { + + item.addEventListener('click', (e) => { + e.preventDefault(); + item.classList.toggle('active'); + }); + + }); + + } + + } + + + // типовые слайдеры + initTypicalSlider() { + + const slidersWraps = document.querySelectorAll('.slider__wrap'); + + if (slidersWraps.length) { + + slidersWraps.forEach(wrap => { + + const slider = wrap.querySelector('.swiper'); + const prev = wrap.querySelector('.swiper-button-prev'); + const next = wrap.querySelector('.swiper-button-next'); + const pagination = wrap.querySelector('.swiper-pagination'); + + let swiper1 = new Swiper(slider, { + navigation: { + nextEl: next, + prevEl: prev, + }, + pagination: { + el: pagination, + clickable: true, + }, + slidesPerView: 1, + spaceBetween: 20, + observer: true, + observeParents: true, + observeSlideChildren: true, + breakpoints: { + 480: { + slidesPerView: 1.5, + }, + 640: { + slidesPerView: 2, + }, + 780: { + slidesPerView: 2.5, + }, + 920: { + slidesPerView: 3, + }, + 1024: { + slidesPerView: 3.4 + }, + 1200: { + slidesPerView: 4, + } + } + }); + + }); + + } + + } + + + // метод, делающий число удобночитаемым (добавляет пробел справа через каждые 3 цифры) + prettify(num) { + const withoutSpace = num.replace(/[^\d]/g, ''); //убирает все символы; + return withoutSpace.replace(/(?!^)(?=(?:\d{3})+(?:\.|$))/gm, ' '); //ставит пробелы; + } + + + // фильтры на главном экране + controlFilters() { + + const heroFilters = document.querySelectorAll('.js_hero_filter'); + const heroSearchBtns = document.querySelectorAll('.js_hero_search_btn'); + + if (heroFilters.length) { + + heroFilters.forEach(filter => { + + const heroFilterInput = filter.querySelector('.js_hero_filter_input'); + const heroFilterCurrent = filter.querySelector('.js_hero_filter_current'); + const heroFilterItems = filter.querySelectorAll('.hero-filter__item'); + const heroFilterFields = filter.querySelectorAll('.js_hero_filter_field'); + const heroFilterFrom = filter.querySelector('.js_hero_filter_from'); + const heroFilterTo = filter.querySelector('.js_hero_filter_to'); + const heroFilterReset = filter.querySelector('.js_hero_filter_reset'); + + heroFilterCurrent.addEventListener('click', () => { + + if (filter.classList.contains('active')) { + + filter.classList.remove('active'); + + heroSearchBtns.forEach(btn => { + btn.disabled = false; + }); + + } else { + + heroFilters.forEach(filter => { + filter.classList.remove('active'); + }); + + filter.classList.add('active'); + + heroSearchBtns.forEach(btn => { + btn.disabled = true; + }); + + } + + }); + + if (heroFilterItems.length) { + + heroFilterItems.forEach(item => { + + item.addEventListener('click', () => { + + heroFilterCurrent.textContent = item.textContent; + heroFilterInput.value = item.dataset.val; + filter.classList.remove('active'); + + heroSearchBtns.forEach(btn => { + btn.disabled = false; + }); + + }); + + }); + + } + + if (heroFilterFields.length) { + + const heroFilterMin = heroFilterFrom.dataset.min; + const heroFilterMax = heroFilterTo.dataset.max; + + let heroFilterFromVal; + let heroFilterToVal; + + heroFilterFields.forEach(field => { + + field.addEventListener('input', () => { + + field.value = this.prettify(field.value); + + heroFilterReset.classList.remove('active'); + + heroFilterFields.forEach(field => { + + if (field.value != "") { + heroFilterReset.classList.add('active'); + } + + }); + + }); + + }); + + heroFilterFrom.addEventListener('change', () => { + + heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); + heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); + + if (heroFilterToVal != '' && heroFilterFromVal > heroFilterToVal) { + + heroFilterFrom.value = heroFilterTo.value; + + } else if (heroFilterFromVal < +heroFilterMin) { + + heroFilterFrom.value = this.prettify(heroFilterMin); + + } else if (heroFilterFromVal > +heroFilterMax) { + + heroFilterFrom.value = this.prettify(heroFilterMax); + + } + + }); + + heroFilterTo.addEventListener('change', () => { + + heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); + heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); + + if (heroFilterFromVal != '' && heroFilterToVal < heroFilterFromVal) { + + heroFilterTo.value = heroFilterFrom.value; + + } else if (heroFilterToVal < +heroFilterMin) { + + heroFilterTo.value = this.prettify(heroFilterMax); + + } else if (heroFilterToVal > +heroFilterMax) { + + heroFilterTo.value = this.prettify(heroFilterMax); + + } + + }); + + heroFilterReset.addEventListener('click', () => { + + heroFilterFields.forEach(field => { + field.value = ''; + }); + + heroFilterReset.classList.remove('active'); + + }); + } + + }); + + document.addEventListener('click', (e) => { + + if (!e.target.closest('.js_hero_filter_dropdown') && !e.target.closest('.js_hero_filter_current')) { + + heroFilters.forEach(filter => { + filter.classList.remove('active'); + }); + + heroSearchBtns.forEach(btn => { + btn.disabled = false; + }); + + } + + }); + + } + + } + + + // открытие/закрытие типовых поп-апов + controlPopups() { + + const popupShowBtns = document.querySelectorAll('[data-btn]'); + const popups = document.querySelectorAll('[data-popup]'); + + if (popupShowBtns.length) { + + popupShowBtns.forEach(btn => { + + btn.addEventListener('click', (e) => { + + e.preventDefault(); + + popups.forEach(popup => { + + popup.classList.remove('active'); // если какойто поп-ап открыт, то закрываем его; + this.unfixBodyPosition(); + + if (btn.dataset.btn == popup.dataset.popup) { + popup.classList.add('active'); + this.fixBodyPosition(); + } + + }); + + + }); + + }); + + popups.forEach(popup => { + + const popupCloseBtns = popup.querySelectorAll('.js_popup_close'); + + popupCloseBtns.forEach(btn => { + + btn.addEventListener('click', (e) => { + e.preventDefault(); + popup.classList.remove('active'); + this.unfixBodyPosition(); + }); + + }); + + popup.addEventListener('click', (e) => { + + if (e.target == popup) { + + popup.classList.remove('active'); + this.unfixBodyPosition(); + } + + }); + + }); + + } + } + + + // открытие/закрытие поп-апа 'обратный звонок' + controlContactUsPopup() { + + const contactUsBtn = document.querySelector('.js_btn_contact_us'); + const contactUsPopup = document.querySelector('.js_contact_us'); + + if (contactUsPopup) { + + const contactUsPopupCloseBtns = contactUsPopup.querySelectorAll('.js_contact_us_close'); + + contactUsBtn.addEventListener('click', (e) => { + + e.preventDefault(); + + if (contactUsPopup.classList.contains('active')) { + contactUsPopup.classList.remove('active'); + } else { + contactUsPopup.classList.add('active'); + } + + }); + + contactUsPopupCloseBtns.forEach(btn => { + btn.addEventListener('click', () => { + contactUsPopup.classList.remove('active'); + }); + }); + + + document.addEventListener('click', (e) => { + + if (!e.target.closest('.js_contact_us') && !e.target.closest('.js_btn_contact_us')) { + contactUsPopup.classList.remove('active'); + } + + }); + + } + + } + + + // валидатор форм + validateForm(input) { + + // функция добавления ошибки + const createError = (text) => { + + input.classList.add('error'); + input.classList.remove('no-error'); + + if (input.closest('label').querySelector('span.error')) { + input.closest('label').querySelector('span.error').remove(); + input.closest('label').insertAdjacentHTML('beforeend', `${text}`); + } else { + input.closest('label').insertAdjacentHTML('beforeend', `${text}`); + } + + } + + // функция удаления ошибки + const removeError = () => { + + input.classList.remove('error'); + input.classList.add('no-error'); + + if (input.closest('label').querySelector('span.error')) { + input.closest('label').querySelector('span.error').remove(); + } + + } + + // проверяем на правильность заполнения поля 'Телефон' + if (input.classList.contains('js_input_phone') && input.value == "") { + createError('Заполните, пожалуйста, поле'); + } else if (input.classList.contains('js_input_phone') && input.value.search(this.patternPhone) == 0) { + removeError(); + } else if (input.classList.contains('js_input_phone')) { + createError('Укажите, пожалуйста, корректный телефон'); + } + + // проверяем правильность заполнения поля 'Электронная почта' + if (input.classList.contains('js_input_email') && input.value == "") { + createError('Заполните, пожалуйста, поле'); + } else if (input.classList.contains('js_input_email') && input.value.search(this.patternEmail) == 0) { + removeError(); + } else if (input.classList.contains('js_input_email')) { + createError('Укажите, пожалуйста, корректный e-mail'); + } + + } + + + // отправка форм + sendForm(formEl, success) { + + const form = document.querySelector(formEl); + + if (form) { + + form.addEventListener('submit', async (e) => { + + e.preventDefault(); + + const formInputs = form.querySelectorAll('input'); + const formBtn = form.querySelector('.js_form_btn'); + + formInputs.forEach(input => { // перебираем все инпуты в форме; + + this.validateForm(input); + + input.addEventListener('input', () => { + this.validateForm(input); + }); + + }); + + if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); + + // сюда пишем команды, которые должны сработать после успешной валидации; + + console.log('validate'); + formBtn.classList.add('btn-animate'); + formBtn.disabled = true; + + const formData = new FormData(form); + + console.log(...formData); + + const response = await fetch(e.target.action, { + method: e.target.method, + body: formData + }); + + if (response.ok) { + + setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; + + console.log('Отправлено'); + formBtn.classList.remove('btn-animate'); + formBtn.disabled = false; + if (document.querySelector('[data-popup="feedback"]')) { + document.querySelector('[data-popup="feedback"]').classList.remove('active'); + } + if (document.querySelector('[data-popup="viewing"]')) { + document.querySelector('[data-popup="viewing"]').classList.remove('active'); + } + document.querySelector(success).classList.add('active'); + this.fixBodyPosition(); + form.reset(); + + formInputs.forEach(input => { + input.classList.remove('no-error'); + }); + + }, 2000) + + } else { + formBtn.classList.remove('btn-animate'); + formBtn.disabled = false; + alert('Ошибка'); + } + + } else { + console.log('no-validate'); + form.querySelector('.error').focus(); //фокус к полю с ошибкой; + } + + }); + + } + + } + + //отправка предложения по e-mail + sendOffer() { + + const form = document.querySelector('.js_popup_sending_form'); + + if (form) { + + form.addEventListener('submit', async (e) => { + + e.preventDefault(); + + const formInputs = form.querySelectorAll('input'); + const formBtn = form.querySelector('.js_form_btn'); + + formInputs.forEach(input => { // перебираем все инпуты в форме; + + this.validateForm(input); + + input.addEventListener('input', () => { + this.validateForm(input); + }); + + }); + + if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); + + // сюда пишем команды, которые должны сработать после успешной валидации; + + console.log('validate'); + formBtn.classList.add('btn-animate'); + formBtn.disabled = true; + + const formData = new FormData(form); + + console.log(...formData); + + const response = await fetch(e.target.action, { + method: e.target.method, + body: formData + }); + + if (response.ok) { + + setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; + + console.log('Отправлено'); + formBtn.classList.remove('btn-animate'); + formBtn.disabled = false; + if (document.querySelector('[data-popup="sending"]')) { + document.querySelector('[data-popup="sending"]').classList.remove('active'); + } + this.fixBodyPosition(); + form.reset(); + + formInputs.forEach(input => { + input.classList.remove('no-error'); + }); + + }, 2000) + + } else { + formBtn.classList.remove('btn-animate'); + formBtn.disabled = false; + alert('Ошибка'); + } + + } else { + console.log('no-validate'); + form.querySelector('.error').focus(); //фокус к полю с ошибкой; + } + + }); + + } + + } + + + // карта на странице 'ЖК' +/* setComplexMap(id, coords, caption) { + + if (document.querySelector('#' + id)) { + + // Дождёмся загрузки API и готовности DOM. + ymaps.ready(init); + + function init() { + const map = new ymaps.Map(id, { + // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования. + center: coords, + zoom: 16, + controls: [] + }); + + // Создаём макет содержимого. + const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( + '
$[properties.iconContent]
' + ); + + // Создание макета содержимого хинта. + // Макет создается через фабрику макетов с помощью текстового шаблона. + const HintLayout = ymaps.templateLayoutFactory.createClass("
" + + "{{ properties.object }}" + "
", { + // Определяем метод getShape, который + // будет возвращать размеры макета хинта. + // Это необходимо для того, чтобы хинт автоматически + // сдвигал позицию при выходе за пределы карты. + getShape: function () { + let el = this.getElement(), + result = null; + if (el) { + var firstChild = el.firstChild; + result = new ymaps.shape.Rectangle( + new ymaps.geometry.pixel.Rectangle([ + [0, 0], + [firstChild.offsetWidth, firstChild.offsetHeight] + ]) + ); + } + return result; + } + } + ); + + // метка + const placemark = new ymaps.Placemark(coords, { + // hintContent: caption, + // balloonContent: caption, + iconContent: '1', + // address: caption, + object: caption + }, { + iconLayout: 'default#imageWithContent', + iconImageHref: 'images/mark-complex.svg', + iconImageSize: [52, 67], + iconImageOffset: [-26, -67], + iconContentOffset: [0, 17], + iconContentLayout: MyIconContentLayout, + hintLayout: HintLayout + }); + + map.geoObjects.add(placemark); + + } + + } + + } +*/ + + // фильтры и сортировка на странице 'каталог' + setCatalogSorts() { + + const sortGroups = document.querySelectorAll('.js_sort_group'); + + if (sortGroups.length) { + + sortGroups.forEach(group => { + + const sortGroupInput = group.querySelector('.js_sort_group_input'); + const sortGroupCurrent = group.querySelector('.js_sort_group_current'); + const sortGroupList = group.querySelector('.js_sort_group_list'); + const sortGroupItems = group.querySelectorAll('.js_sort_group_item'); + + const sendRequest = () => { + + const spinner = document.querySelector('.spinner'); // спиннер; + + spinner.classList.add('active'); + document.body.classList.add('overlay'); + /*this.fixBodyPosition(); + + fetch('test.json') + .then(response => response.json()) + .then(data => { + + console.log() + + setTimeout(() => { //имитация ответа сервера + + spinner.classList.remove('active'); + document.body.classList.remove('overlay'); + this.unfixBodyPosition(); + + }, 3000); + + }) + .catch(err => { + console.log(err); + }); + + */ + spinner.classList.remove('active'); + document.body.classList.remove('overlay'); + + + }; + + sortGroupCurrent.addEventListener('click', () => { + + if (group.classList.contains('active')) { + + group.classList.remove('active'); + + } else { + + sortGroups.forEach(group => { + group.classList.remove('active'); + }); + + group.classList.add('active'); + + } + + }); + + sortGroupItems.forEach(item => { + + item.addEventListener('click', () => { + + sortGroupItems.forEach(item => { + item.classList.remove('active'); + }); + + item.classList.add('active'); + sortGroupCurrent.textContent = item.textContent; + sortGroupInput.value = item.dataset.val; + group.classList.remove('active'); + + sendRequest(); + + }); + + }); + + }); + + document.addEventListener('click', (e) => { + + if (!e.target.closest('.js_sort_group_list') && !e.target.closest('.js_sort_group_current')) { + + sortGroups.forEach(group => { + group.classList.remove('active'); + }); + + } + + }); + + } + + } + + + // слайдер на странице жк и на странице предложения + initIntroSlider() { + + let swiper3 = new Swiper('.intro__swiper', { + navigation: { + nextEl: '.swiper-button-next', + prevEl: '.swiper-button-prev', + }, + pagination: { + el: '.swiper-pagination', + clickable: true, + }, + slidesPerView: 1.1, + spaceBetween: 20, + breakpoints: { + 480: { + slidesPerView: 1.5, + }, + 640: { + slidesPerView: 1.75, + }, + 780: { + slidesPerView: 2.15, + }, + 1024: { + slidesPerView: 3.5, + }, + 1200: { + slidesPerView: 1, + } + } + }); + + } + + + // табы на странице предложения + setTabs(tabs, items) { + + const offerSideTabs = document.querySelectorAll(tabs); + const offerSideItems = document.querySelectorAll(items); + + if (offerSideTabs) { + + offerSideTabs.forEach(tab => { + + tab.addEventListener('click', () => { + + offerSideTabs.forEach(tab => { + tab.classList.remove('active'); + }); + + tab.classList.add('active'); + + offerSideItems.forEach(item => { + + item.classList.remove('active', 'fade'); + + if (tab.dataset.tab == item.dataset.item) { + item.classList.add('active', 'fade'); + } + + }); + + }); + + }); + + } + + } + + + // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения + sontrolOfferSidePopup() { + + const offerSideItems = document.querySelectorAll('.js_offer_side_item'); + const offerSidePopupTabs = document.querySelectorAll('.js_offer_side_popup_tab'); + const offerSidePopupItems = document.querySelectorAll('.js_offer_side_popup_item'); + + if (offerSideItems) { + + offerSideItems.forEach(item => { + + const offerSideItemBtn = item.querySelector('.js_offer_side_item_btn'); + + offerSideItemBtn.addEventListener('click', (e) => { + + e.preventDefault(); + + offerSidePopupTabs.forEach(tab => { + + tab.classList.remove('active'); + + if (item.dataset.item == tab.dataset.tab) { + tab.classList.add('active'); + } + + }); + + offerSidePopupItems.forEach(el => { + + el.classList.remove('active', 'fade'); + + if (item.dataset.item == el.dataset.item) { + el.classList.add('active', 'fade'); + } + + }); + + }); + + }); + + } + + } + + + // галлерея + setCustomGallery() { + + let swiper4 = new Swiper(".img-viewer__thumbs-swiper", { + slidesPerView: 3, + spaceBetween: 8, + // freeMode: true, + observer: true, + observeParents: true, + observeSlideChildren: true, + breakpoints: { + 640: { + spaceBetween: 10, + }, + }, + }); + + let swiper5 = new Swiper(".img-viewer__slider .swiper", { + navigation: { + nextEl: ".img-viewer__slider .swiper-button-next", + prevEl: ".img-viewer__slider .swiper-button-prev", + }, + slidesPerView: 1, + spaceBetween: 20, + thumbs: { + swiper: swiper4 + }, + observer: true, + observeParents: true, + observeSlideChildren: true, + }); + + if (document.querySelector('.js_intro_item_btn')) { + + const imgViewer = document.querySelector('.js_img_viewer'); + const imgViewerCloses = imgViewer.querySelectorAll('.js_img_viewer_close'); + const imgViewerCaption = imgViewer.querySelector('.js_img_viewer_caption'); + + const imgViewerSliderSwiper = imgViewer.querySelector('.js_img_viewer_slider_swiper'); + const imgViewerSliderSwiperWrap = imgViewerSliderSwiper.querySelector('.js_img_viewer_slider_swiper .swiper-wrapper'); + + const imgViewerThumbsSwiper = imgViewer.querySelector('.js_img_viewer_thumbs_swiper'); + const imgViewerThumbsSwiperWrap = imgViewerThumbsSwiper.querySelector('.js_img_viewer_thumbs_swiper .swiper-wrapper'); + + const introItemBtns = document.querySelectorAll('.js_intro_item_btn'); + + introItemBtns.forEach((btn, i) => { + + btn.addEventListener('click', (e) => { + + e.preventDefault(); + + imgViewer.classList.add('active'); + this.fixBodyPosition(); + + imgViewerSliderSwiperWrap.innerHTML = ''; + imgViewerThumbsSwiperWrap.innerHTML = ''; + imgViewerCaption.textContent = ''; + + + introItemBtns.forEach(btn => { + + imgViewerSliderSwiperWrap.insertAdjacentHTML('beforeend', ` +
+ +
` + ); + + imgViewerThumbsSwiperWrap.insertAdjacentHTML('beforeend', ` +
+ +
` + ); + + }); + + swiper4.update(); + swiper5.update(); + swiper5.slideTo(i); + imgViewerCaption.textContent = btn.dataset.caption; + + }); + + }); + + swiper5.on('slideChange', function () { + imgViewerCaption.textContent = introItemBtns[swiper5.realIndex].dataset.caption; + }); + + imgViewerCloses.forEach(close => { + + close.addEventListener('click', () => { + + imgViewer.classList.remove('active'); + this.unfixBodyPosition(); + + }); + + }); + + } + + } + + + // куки + setCookies() { + + const cookies = document.querySelector('.js_cookies'); + const cookiesBtn = document.querySelector('.js_cookies_confirm'); + const cookiesTrigger = document.querySelector('.js_btn_cookies'); + + if (cookiesTrigger) { + + cookiesTrigger.addEventListener('click', () => { + cookies.classList.add('active'); + }); + + }; + + if (cookies) { + + cookiesBtn.addEventListener('click', () => { + cookies.classList.remove('active'); + }); + + }; + + } + + + // карта на странице карт; + /* + //setGeneralMap() { + + if (document.querySelector('#general-map')) { + + ymaps.ready(init); // Дождёмся загрузки API и готовности DOM; + + function init() { + + const myMap = new ymaps.Map('general-map', { // Создание экземпляра карты и его привязка к контейнеру с заданным id; + center: [55.752933963675126, 37.52233749962665], // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования; + zoom: 10, + controls: [] // Скрываем элементы управления на карте; + }); + + // Создаём макет содержимого. + const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( + '
$[properties.iconContent]
' + ); + + let collection = new ymaps.GeoObjectCollection(null, { // Создаём коллекцию, в которую будемпомещать метки (что-то типа массива); + // preset: 'islands#yellowIcon' + }); + + let collectionCoords = [ // Создаём массив с координатами (координаты должны располагаться в том же порядке, что и адреса в списке на сайте); + [55.867783219108354, 37.392867499999916], + [55.728043075486504, 37.73937949999994], + [55.72624100423305, 37.476078499999964], + [55.80751105044832, 37.449622999999974], + [55.601783098948836, 37.36700499999998], + [55.86086502152225, 37.540348999999964], + [55.784961528728715, 37.56188599999996], + [55.63910010399773, 37.319407999999996], + [55.55819256767507, 37.55711549999994], + [55.79829252928473, 37.52063549999999], + ]; + + for (let i = 0, l = collectionCoords.length; i < l; i++) { // C помощью цикла добавляем все метки в коллекцию; + collection.add(new ymaps.Placemark(collectionCoords[i])); + collection.get(i).properties.set('iconContent', `${i + 1}`); // Добавляем каждой метке порядковый номер, записываем его в свойство 'iconContent'; + } + + myMap.geoObjects.add(collection); // Добавляем коллекцию с метками на карту; + + collection.options.set('iconLayout', 'default#imageWithContent'); // Необходимо указать данный тип макета; + collection.options.set('iconImageHref', 'images/mark-complex.svg'); // Своё изображение иконки метки; + collection.options.set('iconImageSize', [52, 67]); // Размеры метки; + collection.options.set('iconImageOffset', [-26, -67]); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); + collection.options.set('iconContentOffset', [0, 17]); + collection.options.set('iconContentLayout', MyIconContentLayout); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); + + const pageMapBar = document.querySelector('.js_page_map_bar'); + const pageMapBarBtn = pageMapBar.querySelector('.js_page_map_bar_btn'); + const pageMapBarList = pageMapBar.querySelector('.js_page_map_bar_list'); + const pageMapBarCards = pageMapBar.querySelectorAll('.card-news'); + + const showCard = (i) => { + + pageMapBarCards.forEach((card, k) => { + + card.classList.remove('active'); + + if (i == k) { + card.classList.add('active'); + } + + }); + + }; + + const hidecard = () => { + + pageMapBarCards.forEach(card => { + card.classList.remove('active'); + }); + + } + + let pageMapBarItems; + + pageMapBarBtn.addEventListener('click', () => { + pageMapBar.classList.toggle('active'); + }); + + pageMapBarList.addEventListener('click', (e) => { + + if (e.target.closest('.page-map-bar__item')) { + + pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); + + pageMapBarItems.forEach((item, i) => { + + if (e.target == item && e.target.classList.contains('active')) { + + item.classList.remove('active'); + + hidecard(); + + } else if (e.target == item) { + + pageMapBarItems.forEach(item => { + item.classList.remove('active'); + }); + + item.classList.add('active'); + + let offsetCoords = collection.get(i).geometry.getCoordinates(); + + offsetCoords = [ + offsetCoords[0] - 0.0025, + offsetCoords[1] + ]; + + myMap.setZoom(16); + // myMap.setCenter(collection.get(i).geometry.getCoordinates()); + myMap.setCenter(offsetCoords); + + showCard(i); + + } + + }); + } + + }); + + collection.events.add('click', function (e) { + + for (let i = 0, l = collection.getLength(); i < l; i++) { + + if (e.get('target') == collection.get(i)) { + + pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); + + pageMapBarItems.forEach((item) => { + pageMapBar.classList.add('active'); + item.classList.remove('active'); + }); + + pageMapBarItems[i].classList.add('active'); + + showCard(i); + + } + + } + + }); + + } + + } + + };*/ + + + // аккордеон в футере + setFooterSpoilers() { + + const items = document.querySelectorAll('.js_footer_col'); + + items.forEach(item => { + + const itemTitle = item.querySelector('.js_footer_caption'); + const itemContent = item.querySelector('.js_footer_block'); + + const blockToggle = (block, duration) => { + + if (window.getComputedStyle(block).display == "none" && !block.classList.contains('smooth')) { + + block.style.display = "block"; + + const blockHeight = block.offsetHeight; + + block.style.height = 0; + block.style.overflow = "hidden"; + block.style.transition = `height ${duration}ms ease`; + block.classList.add('smooth'); + block.offsetHeight; + block.style.height = `${blockHeight}px`; + + setTimeout(() => { + + block.classList.remove('smooth'); + block.style.height = ''; + block.style.transition = ''; + block.style.overflow = ''; + + }, duration); + + } else if (!block.classList.contains('smooth')) { + + block.style.height = `${block.offsetHeight}px`; + block.offsetHeight; + block.style.height = 0; + block.style.overflow = "hidden"; + block.style.transition = `height ${duration}ms ease`; + block.classList.add('smooth'); + + setTimeout(() => { + + block.classList.remove('smooth'); + block.style.display = "none"; + block.style.height = ''; + block.style.transition = ''; + block.style.overflow = ''; + + }, duration); + + } + + }; + + itemTitle.addEventListener('click', (e) => { + itemTitle.classList.toggle('active'); + blockToggle(itemContent, 300); + }); + + }); + + } + + + // слайдер с партнёрами; + initPartnerslSlider() { + + const slider = document.querySelector('.partners__swiper'); + + if (slider) { + + let swiper6; + + const initSlider = () => { + + swiper6 = new Swiper(slider, { + // scrollbar: { + // el: '.swiper-scrollbar', + // draggable: true, + // }, + slidesPerView: 0.275, + loop: true, + spaceBetween: 20, + freeMode: true, + allowTouchMove: true, + breakpoints: { + 480: { + slidesPerView: 0.4, + }, + 640: { + slidesPerView: 0.65, + }, + 780: { + slidesPerView: 0.65, + }, + 1024: { + slidesPerView: 0.8, + }, + 1200: { + slidesPerView: 1, + loop: false, + allowTouchMove: false, + } + } + }); + + }; + + initSlider(); + + const updateSlider = () => { + swiper6.destroy(); + initSlider(); + } + + window.addEventListener('resize', () => { + + if (window.innerWidth <= 1200 && slider.dataset.mobile == 'false') { + slider.dataset.mobile = 'true'; + updateSlider(); + } + + if (window.innerWidth > 1200 && slider.dataset.mobile == 'true') { + slider.dataset.mobile = 'false'; + updateSlider(); + } + + }); + + } + + } + +} + + +document.addEventListener('DOMContentLoaded', () => { + + const app = new App(); + app.init(); + +}); diff --git a/public/js/main_new.js b/public/js/main_new.js deleted file mode 100644 index 6e31ea9..0000000 --- a/public/js/main_new.js +++ /dev/null @@ -1,1508 +0,0 @@ -// управляющий класс App с методом init(), в котором собраны все используемые методы с комментариями о том, что конкретно делает каждый метод - -class App { - - constructor() { - this.patternPhone = /^(\+7|7|8)?[\s\-]?\(?[489][0-9]{2}\)?[\s\-]?[0-9]{3}[\s\-]?[0-9]{2}[\s\-]?[0-9]{2}$/; // рег. выражение для поля 'телефон'; - this.patternEmail = /^[a-zA-Z0-9._%+-\.]+@[a-z0-9.-]+\.[a-z]{2,}$/i; // рег. выражение для поля 'электронная почта'; - } - - init() { - - console.log('init'); - - this.stickyHeader(); // липкий хедер; - this.controlBurgerMenu(); // бургер-меню; - this.smoothScroll(); // плавный скролл к якорю (smooth scroll); - this.scrollUp(); // кнопка наверх; - this.addToFavorites(); // добавить в избранное (звёздочка); - this.initTypicalSlider(); // типовые слайдеры; - this.initPartnerslSlider(); // слайдер с партнёрами; - this.controlFilters(); // фильтры на главном экране; - this.controlPopups(); // открытие/закрытие поп-апов; - this.controlContactUsPopup(); // открытие/закрытие поп-апа 'обратный звонок'; - - this.sendForm('.js_popup_feedback_form', '[data-popup="success"]'); // отправка формы в поп-апе обратной связи; - this.sendForm('.js_popup_viewing_form', '[data-popup="success"]'); // отправка формы в поп-апе 'записаться на просмотр'; - this.sendForm('.js_footer_feedback_form', '[data-popup="success"]'); // отправка формы в футере; - this.sendForm('.js_contacts_form', '.js_contacts_success'); // отправка формы на странице контакты; - this.sendForm('.js_popup_sending_form_', '[data-popup="success"]'); - //this.sendOffer(); //отправка предложения по e-mail; - - //this.setGeneralMap(); // карта на странице карт; - this.setComplexMap('complex-map', [55.726591050908745, 37.57244549999999], 'ЖК Садовые кварталы'); // карта на странице 'ЖК'; - this.setComplexMap('offer-map', [55.70851106903402, 37.65864349999999], 'Аренда торгового помещения 321,6 м2'); // карта на странице 'Предложение'; - this.setCatalogSorts(); // сортировка на странице 'каталог'; - this.initIntroSlider(); // слайдер на странице жк и на странице предложения; - this.setTabs('.js_offer_side_tab', '.js_offer_side_item'); // табы с планами объекат и этажа на странице предложения; - this.setTabs('.js_offer_side_popup_tab', '.js_offer_side_popup_item'); // табы с планами объекат и этажа в поп-апе на странице предложения; - this.sontrolOfferSidePopup(); // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения; - this.setCustomGallery(); // галлерея; - this.setCookies() // куки; - this.setFooterSpoilers() // аккордеон в футере; - - } - - // фиксация - fixBodyPosition() { - - setTimeout(function () { - // ставим необходимую задержку, чтобы не было «конфликта» в случае, если функция фиксации вызывается сразу после расфиксации (расфиксация отменяет действия расфиксации из-за одновременного действия) - - if (!document.body.hasAttribute('data-body-scroll-fix')) { - - // получаем позицию прокрутки - let scrollPosition = window.pageYOffset || document.documentElement.scrollTop; - - // ставим нужные стили - document.body.setAttribute('data-body-scroll-fix', scrollPosition); // Cтавим атрибут со значением прокрутки - document.body.style.overflow = 'hidden'; - document.body.style.position = 'fixed'; - document.body.style.top = '-' + scrollPosition + 'px'; - document.body.style.left = '0'; - document.body.style.width = '100%'; - - if (window.innerWidth >= 1200) { - document.body.style.paddingRight = '8px'; - } - } - - }, 15); // можно задержку ещё меньше, но работает хорошо именно с этим значением на всех устройствах и браузерах - - } - - - // расфиксация - unfixBodyPosition() { - - if (document.body.hasAttribute('data-body-scroll-fix')) { - - // получаем позицию прокрутки из атрибута - let scrollPosition = document.body.getAttribute('data-body-scroll-fix'); - - // удаляем атрибут - document.body.removeAttribute('data-body-scroll-fix'); - - // удаляем ненужные стили - document.body.style.overflow = ''; - document.body.style.position = ''; - document.body.style.top = ''; - document.body.style.left = ''; - document.body.style.width = ''; - document.body.style.paddingRight = ''; - - // прокручиваем страницу на полученное из атрибута значение - window.scroll(0, scrollPosition); - - } - - } - - - // бургер-меню - controlBurgerMenu() { - - const headerBurger = document.querySelector('.js_header_burger'); - - if (headerBurger) { - - const menu = document.querySelector('.js_menu'); - const menuClose = menu.querySelector('.js_menu_close'); - - headerBurger.addEventListener('click', () => { - menu.classList.add('active'); - this.fixBodyPosition(); - }); - - menu.addEventListener('click', (e) => { - - if (e.target == menu) { - menu.classList.remove('active'); - this.unfixBodyPosition(); - } - - }); - - menuClose.addEventListener('click', () => { - menu.classList.remove('active'); - this.unfixBodyPosition(); - }); - - } - - } - - - // липкий хедер - stickyHeader() { - - const header = document.querySelector('.js_header'); - - if (header) { - - window.addEventListener('scroll', () => { - - if (window.scrollY > 200) { - header.classList.add('fixed'); - } else { - header.classList.remove('fixed'); - } - - }); - - }; - - } - - - // плавный скролл к якорю (smooth scroll) - smoothScroll() { - - const smoothLinks = document.querySelectorAll('.js_smooth_link'); - - if (smoothLinks.length) { - - smoothLinks.forEach(link => { - - link.addEventListener('click', function (e) { - - e.preventDefault(); - - let href = this.getAttribute('href').substring(1); - - const scrollTarget = document.getElementById(href); - - // const topOffset = document.querySelector('.header').offsetHeight; - const topOffset = 0; // если не нужен отступ сверху - const elementPosition = scrollTarget.getBoundingClientRect().top; - const offsetPosition = elementPosition - topOffset; - - window.scrollBy({ - top: offsetPosition, - behavior: 'smooth' - }); - - }); - - }); - - } - - } - - - // кнопка наверх - scrollUp() { - - const toTopBtn = document.querySelector('.js_btn_up'); - - if (toTopBtn) { - - toTopBtn.addEventListener('click', function () { - - window.scrollTo({ - top: 0, - behavior: 'smooth' - }); - - }); - - } - - } - - - // добавить в избранное (звёздочка) - addToFavorites() { - - const cardFavorites = document.querySelectorAll('.js_card_favorites'); - - if (cardFavorites.length) { - - cardFavorites.forEach(item => { - - item.addEventListener('click', (e) => { - e.preventDefault(); - item.classList.toggle('active'); - }); - - }); - - } - - } - - - // типовые слайдеры - initTypicalSlider() { - - const slidersWraps = document.querySelectorAll('.slider__wrap'); - - if (slidersWraps.length) { - - slidersWraps.forEach(wrap => { - - const slider = wrap.querySelector('.swiper'); - const prev = wrap.querySelector('.swiper-button-prev'); - const next = wrap.querySelector('.swiper-button-next'); - const pagination = wrap.querySelector('.swiper-pagination'); - - let swiper1 = new Swiper(slider, { - navigation: { - nextEl: next, - prevEl: prev, - }, - pagination: { - el: pagination, - clickable: true, - }, - slidesPerView: 1, - spaceBetween: 20, - observer: true, - observeParents: true, - observeSlideChildren: true, - breakpoints: { - 480: { - slidesPerView: 1.5, - }, - 640: { - slidesPerView: 2, - }, - 780: { - slidesPerView: 2.5, - }, - 920: { - slidesPerView: 3, - }, - 1024: { - slidesPerView: 3.4 - }, - 1200: { - slidesPerView: 4, - } - } - }); - - }); - - } - - } - - - // метод, делающий число удобночитаемым (добавляет пробел справа через каждые 3 цифры) - prettify(num) { - const withoutSpace = num.replace(/[^\d]/g, ''); //убирает все символы; - return withoutSpace.replace(/(?!^)(?=(?:\d{3})+(?:\.|$))/gm, ' '); //ставит пробелы; - } - - - // фильтры на главном экране - controlFilters() { - - const heroFilters = document.querySelectorAll('.js_hero_filter'); - const heroSearchBtns = document.querySelectorAll('.js_hero_search_btn'); - - if (heroFilters.length) { - - heroFilters.forEach(filter => { - - const heroFilterInput = filter.querySelector('.js_hero_filter_input'); - const heroFilterCurrent = filter.querySelector('.js_hero_filter_current'); - const heroFilterItems = filter.querySelectorAll('.hero-filter__item'); - const heroFilterFields = filter.querySelectorAll('.js_hero_filter_field'); - const heroFilterFrom = filter.querySelector('.js_hero_filter_from'); - const heroFilterTo = filter.querySelector('.js_hero_filter_to'); - const heroFilterReset = filter.querySelector('.js_hero_filter_reset'); - - heroFilterCurrent.addEventListener('click', () => { - - if (filter.classList.contains('active')) { - - filter.classList.remove('active'); - - heroSearchBtns.forEach(btn => { - btn.disabled = false; - }); - - } else { - - heroFilters.forEach(filter => { - filter.classList.remove('active'); - }); - - filter.classList.add('active'); - - heroSearchBtns.forEach(btn => { - btn.disabled = true; - }); - - } - - }); - - if (heroFilterItems.length) { - - heroFilterItems.forEach(item => { - - item.addEventListener('click', () => { - - heroFilterCurrent.textContent = item.textContent; - heroFilterInput.value = item.dataset.val; - filter.classList.remove('active'); - - heroSearchBtns.forEach(btn => { - btn.disabled = false; - }); - - }); - - }); - - } - - if (heroFilterFields.length) { - - const heroFilterMin = heroFilterFrom.dataset.min; - const heroFilterMax = heroFilterTo.dataset.max; - - let heroFilterFromVal; - let heroFilterToVal; - - heroFilterFields.forEach(field => { - - field.addEventListener('input', () => { - - field.value = this.prettify(field.value); - - heroFilterReset.classList.remove('active'); - - heroFilterFields.forEach(field => { - - if (field.value != "") { - heroFilterReset.classList.add('active'); - } - - }); - - }); - - }); - - heroFilterFrom.addEventListener('change', () => { - - heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); - heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); - - if (heroFilterToVal != '' && heroFilterFromVal > heroFilterToVal) { - - heroFilterFrom.value = heroFilterTo.value; - - } else if (heroFilterFromVal < +heroFilterMin) { - - heroFilterFrom.value = this.prettify(heroFilterMin); - - } else if (heroFilterFromVal > +heroFilterMax) { - - heroFilterFrom.value = this.prettify(heroFilterMax); - - } - - }); - - heroFilterTo.addEventListener('change', () => { - - heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); - heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); - - if (heroFilterFromVal != '' && heroFilterToVal < heroFilterFromVal) { - - heroFilterTo.value = heroFilterFrom.value; - - } else if (heroFilterToVal < +heroFilterMin) { - - heroFilterTo.value = this.prettify(heroFilterMax); - - } else if (heroFilterToVal > +heroFilterMax) { - - heroFilterTo.value = this.prettify(heroFilterMax); - - } - - }); - - heroFilterReset.addEventListener('click', () => { - - heroFilterFields.forEach(field => { - field.value = ''; - }); - - heroFilterReset.classList.remove('active'); - - }); - } - - }); - - document.addEventListener('click', (e) => { - - if (!e.target.closest('.js_hero_filter_dropdown') && !e.target.closest('.js_hero_filter_current')) { - - heroFilters.forEach(filter => { - filter.classList.remove('active'); - }); - - heroSearchBtns.forEach(btn => { - btn.disabled = false; - }); - - } - - }); - - } - - } - - - // открытие/закрытие типовых поп-апов - controlPopups() { - - const popupShowBtns = document.querySelectorAll('[data-btn]'); - const popups = document.querySelectorAll('[data-popup]'); - - if (popupShowBtns.length) { - - popupShowBtns.forEach(btn => { - - btn.addEventListener('click', (e) => { - - e.preventDefault(); - - popups.forEach(popup => { - - popup.classList.remove('active'); // если какойто поп-ап открыт, то закрываем его; - this.unfixBodyPosition(); - - if (btn.dataset.btn == popup.dataset.popup) { - popup.classList.add('active'); - this.fixBodyPosition(); - } - - }); - - - }); - - }); - - popups.forEach(popup => { - - const popupCloseBtns = popup.querySelectorAll('.js_popup_close'); - - popupCloseBtns.forEach(btn => { - - btn.addEventListener('click', (e) => { - e.preventDefault(); - popup.classList.remove('active'); - this.unfixBodyPosition(); - }); - - }); - - popup.addEventListener('click', (e) => { - - if (e.target == popup) { - - popup.classList.remove('active'); - this.unfixBodyPosition(); - } - - }); - - }); - - } - } - - - // открытие/закрытие поп-апа 'обратный звонок' - controlContactUsPopup() { - - const contactUsBtn = document.querySelector('.js_btn_contact_us'); - const contactUsPopup = document.querySelector('.js_contact_us'); - - if (contactUsPopup) { - - const contactUsPopupCloseBtns = contactUsPopup.querySelectorAll('.js_contact_us_close'); - - contactUsBtn.addEventListener('click', (e) => { - - e.preventDefault(); - - if (contactUsPopup.classList.contains('active')) { - contactUsPopup.classList.remove('active'); - } else { - contactUsPopup.classList.add('active'); - } - - }); - - contactUsPopupCloseBtns.forEach(btn => { - btn.addEventListener('click', () => { - contactUsPopup.classList.remove('active'); - }); - }); - - - document.addEventListener('click', (e) => { - - if (!e.target.closest('.js_contact_us') && !e.target.closest('.js_btn_contact_us')) { - contactUsPopup.classList.remove('active'); - } - - }); - - } - - } - - - // валидатор форм - validateForm(input) { - - // функция добавления ошибки - const createError = (text) => { - - input.classList.add('error'); - input.classList.remove('no-error'); - - if (input.closest('label').querySelector('span.error')) { - input.closest('label').querySelector('span.error').remove(); - input.closest('label').insertAdjacentHTML('beforeend', `${text}`); - } else { - input.closest('label').insertAdjacentHTML('beforeend', `${text}`); - } - - } - - // функция удаления ошибки - const removeError = () => { - - input.classList.remove('error'); - input.classList.add('no-error'); - - if (input.closest('label').querySelector('span.error')) { - input.closest('label').querySelector('span.error').remove(); - } - - } - - // проверяем на правильность заполнения поля 'Телефон' - if (input.classList.contains('js_input_phone') && input.value == "") { - createError('Заполните, пожалуйста, поле'); - } else if (input.classList.contains('js_input_phone') && input.value.search(this.patternPhone) == 0) { - removeError(); - } else if (input.classList.contains('js_input_phone')) { - createError('Укажите, пожалуйста, корректный телефон'); - } - - // проверяем правильность заполнения поля 'Электронная почта' - if (input.classList.contains('js_input_email') && input.value == "") { - createError('Заполните, пожалуйста, поле'); - } else if (input.classList.contains('js_input_email') && input.value.search(this.patternEmail) == 0) { - removeError(); - } else if (input.classList.contains('js_input_email')) { - createError('Укажите, пожалуйста, корректный e-mail'); - } - - } - - - // отправка форм - sendForm(formEl, success) { - - const form = document.querySelector(formEl); - - if (form) { - - form.addEventListener('submit', async (e) => { - - e.preventDefault(); - - const formInputs = form.querySelectorAll('input'); - const formBtn = form.querySelector('.js_form_btn'); - - formInputs.forEach(input => { // перебираем все инпуты в форме; - - this.validateForm(input); - - input.addEventListener('input', () => { - this.validateForm(input); - }); - - }); - - if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); - - // сюда пишем команды, которые должны сработать после успешной валидации; - - console.log('validate'); - formBtn.classList.add('btn-animate'); - formBtn.disabled = true; - - const formData = new FormData(form); - - console.log(...formData); - - const response = await fetch(e.target.action, { - method: e.target.method, - body: formData - }); - - if (response.ok) { - - setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; - - console.log('Отправлено'); - formBtn.classList.remove('btn-animate'); - formBtn.disabled = false; - if (document.querySelector('[data-popup="feedback"]')) { - document.querySelector('[data-popup="feedback"]').classList.remove('active'); - } - if (document.querySelector('[data-popup="viewing"]')) { - document.querySelector('[data-popup="viewing"]').classList.remove('active'); - } - document.querySelector(success).classList.add('active'); - this.fixBodyPosition(); - form.reset(); - - formInputs.forEach(input => { - input.classList.remove('no-error'); - }); - - }, 2000) - - } else { - formBtn.classList.remove('btn-animate'); - formBtn.disabled = false; - alert('Ошибка'); - } - - } else { - console.log('no-validate'); - form.querySelector('.error').focus(); //фокус к полю с ошибкой; - } - - }); - - } - - } - - //отправка предложения по e-mail - sendOffer() { - - const form = document.querySelector('.js_popup_sending_form'); - - if (form) { - - form.addEventListener('submit', async (e) => { - - e.preventDefault(); - - const formInputs = form.querySelectorAll('input'); - const formBtn = form.querySelector('.js_form_btn'); - - formInputs.forEach(input => { // перебираем все инпуты в форме; - - this.validateForm(input); - - input.addEventListener('input', () => { - this.validateForm(input); - }); - - }); - - if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); - - // сюда пишем команды, которые должны сработать после успешной валидации; - - console.log('validate'); - formBtn.classList.add('btn-animate'); - formBtn.disabled = true; - - const formData = new FormData(form); - - console.log(...formData); - - const response = await fetch(e.target.action, { - method: e.target.method, - body: formData - }); - - if (response.ok) { - - setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; - - console.log('Отправлено'); - formBtn.classList.remove('btn-animate'); - formBtn.disabled = false; - if (document.querySelector('[data-popup="sending"]')) { - document.querySelector('[data-popup="sending"]').classList.remove('active'); - } - this.fixBodyPosition(); - form.reset(); - - formInputs.forEach(input => { - input.classList.remove('no-error'); - }); - - }, 2000) - - } else { - formBtn.classList.remove('btn-animate'); - formBtn.disabled = false; - alert('Ошибка'); - } - - } else { - console.log('no-validate'); - form.querySelector('.error').focus(); //фокус к полю с ошибкой; - } - - }); - - } - - } - - - // карта на странице 'ЖК' - setComplexMap(id, coords, caption) { - - if (document.querySelector('#' + id)) { - - // Дождёмся загрузки API и готовности DOM. - ymaps.ready(init); - - function init() { - const map = new ymaps.Map(id, { - // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования. - center: coords, - zoom: 16, - controls: [] - }); - - // Создаём макет содержимого. - const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( - '
$[properties.iconContent]
' - ); - - // Создание макета содержимого хинта. - // Макет создается через фабрику макетов с помощью текстового шаблона. - const HintLayout = ymaps.templateLayoutFactory.createClass("
" + - "{{ properties.object }}" + "
", { - // Определяем метод getShape, который - // будет возвращать размеры макета хинта. - // Это необходимо для того, чтобы хинт автоматически - // сдвигал позицию при выходе за пределы карты. - getShape: function () { - let el = this.getElement(), - result = null; - if (el) { - var firstChild = el.firstChild; - result = new ymaps.shape.Rectangle( - new ymaps.geometry.pixel.Rectangle([ - [0, 0], - [firstChild.offsetWidth, firstChild.offsetHeight] - ]) - ); - } - return result; - } - } - ); - - // метка - const placemark = new ymaps.Placemark(coords, { - // hintContent: caption, - // balloonContent: caption, - iconContent: '1', - // address: caption, - object: caption - }, { - iconLayout: 'default#imageWithContent', - iconImageHref: 'images/mark-complex.svg', - iconImageSize: [52, 67], - iconImageOffset: [-26, -67], - iconContentOffset: [0, 17], - iconContentLayout: MyIconContentLayout, - hintLayout: HintLayout - }); - - map.geoObjects.add(placemark); - - } - - } - - } - - - // фильтры и сортировка на странице 'каталог' - setCatalogSorts() { - - const sortGroups = document.querySelectorAll('.js_sort_group'); - - if (sortGroups.length) { - - sortGroups.forEach(group => { - - const sortGroupInput = group.querySelector('.js_sort_group_input'); - const sortGroupCurrent = group.querySelector('.js_sort_group_current'); - const sortGroupList = group.querySelector('.js_sort_group_list'); - const sortGroupItems = group.querySelectorAll('.js_sort_group_item'); - - const sendRequest = () => { - - const spinner = document.querySelector('.spinner'); // спиннер; - - spinner.classList.add('active'); - document.body.classList.add('overlay'); - /*this.fixBodyPosition(); - - fetch('test.json') - .then(response => response.json()) - .then(data => { - - console.log() - - setTimeout(() => { //имитация ответа сервера - - spinner.classList.remove('active'); - document.body.classList.remove('overlay'); - this.unfixBodyPosition(); - - }, 3000); - - }) - .catch(err => { - console.log(err); - }); - - */ - spinner.classList.remove('active'); - document.body.classList.remove('overlay'); - - - }; - - sortGroupCurrent.addEventListener('click', () => { - - if (group.classList.contains('active')) { - - group.classList.remove('active'); - - } else { - - sortGroups.forEach(group => { - group.classList.remove('active'); - }); - - group.classList.add('active'); - - } - - }); - - sortGroupItems.forEach(item => { - - item.addEventListener('click', () => { - - sortGroupItems.forEach(item => { - item.classList.remove('active'); - }); - - item.classList.add('active'); - sortGroupCurrent.textContent = item.textContent; - sortGroupInput.value = item.dataset.val; - group.classList.remove('active'); - - sendRequest(); - - }); - - }); - - }); - - document.addEventListener('click', (e) => { - - if (!e.target.closest('.js_sort_group_list') && !e.target.closest('.js_sort_group_current')) { - - sortGroups.forEach(group => { - group.classList.remove('active'); - }); - - } - - }); - - } - - } - - - // слайдер на странице жк и на странице предложения - initIntroSlider() { - - let swiper3 = new Swiper('.intro__swiper', { - navigation: { - nextEl: '.swiper-button-next', - prevEl: '.swiper-button-prev', - }, - pagination: { - el: '.swiper-pagination', - clickable: true, - }, - slidesPerView: 1.1, - spaceBetween: 20, - breakpoints: { - 480: { - slidesPerView: 1.5, - }, - 640: { - slidesPerView: 1.75, - }, - 780: { - slidesPerView: 2.15, - }, - 1024: { - slidesPerView: 3.5, - }, - 1200: { - slidesPerView: 1, - } - } - }); - - } - - - // табы на странице предложения - setTabs(tabs, items) { - - const offerSideTabs = document.querySelectorAll(tabs); - const offerSideItems = document.querySelectorAll(items); - - if (offerSideTabs) { - - offerSideTabs.forEach(tab => { - - tab.addEventListener('click', () => { - - offerSideTabs.forEach(tab => { - tab.classList.remove('active'); - }); - - tab.classList.add('active'); - - offerSideItems.forEach(item => { - - item.classList.remove('active', 'fade'); - - if (tab.dataset.tab == item.dataset.item) { - item.classList.add('active', 'fade'); - } - - }); - - }); - - }); - - } - - } - - - // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения - sontrolOfferSidePopup() { - - const offerSideItems = document.querySelectorAll('.js_offer_side_item'); - const offerSidePopupTabs = document.querySelectorAll('.js_offer_side_popup_tab'); - const offerSidePopupItems = document.querySelectorAll('.js_offer_side_popup_item'); - - if (offerSideItems) { - - offerSideItems.forEach(item => { - - const offerSideItemBtn = item.querySelector('.js_offer_side_item_btn'); - - offerSideItemBtn.addEventListener('click', (e) => { - - e.preventDefault(); - - offerSidePopupTabs.forEach(tab => { - - tab.classList.remove('active'); - - if (item.dataset.item == tab.dataset.tab) { - tab.classList.add('active'); - } - - }); - - offerSidePopupItems.forEach(el => { - - el.classList.remove('active', 'fade'); - - if (item.dataset.item == el.dataset.item) { - el.classList.add('active', 'fade'); - } - - }); - - }); - - }); - - } - - } - - - // галлерея - setCustomGallery() { - - let swiper4 = new Swiper(".img-viewer__thumbs-swiper", { - slidesPerView: 3, - spaceBetween: 8, - // freeMode: true, - observer: true, - observeParents: true, - observeSlideChildren: true, - breakpoints: { - 640: { - spaceBetween: 10, - }, - }, - }); - - let swiper5 = new Swiper(".img-viewer__slider .swiper", { - navigation: { - nextEl: ".img-viewer__slider .swiper-button-next", - prevEl: ".img-viewer__slider .swiper-button-prev", - }, - slidesPerView: 1, - spaceBetween: 20, - thumbs: { - swiper: swiper4 - }, - observer: true, - observeParents: true, - observeSlideChildren: true, - }); - - if (document.querySelector('.js_intro_item_btn')) { - - const imgViewer = document.querySelector('.js_img_viewer'); - const imgViewerCloses = imgViewer.querySelectorAll('.js_img_viewer_close'); - const imgViewerCaption = imgViewer.querySelector('.js_img_viewer_caption'); - - const imgViewerSliderSwiper = imgViewer.querySelector('.js_img_viewer_slider_swiper'); - const imgViewerSliderSwiperWrap = imgViewerSliderSwiper.querySelector('.js_img_viewer_slider_swiper .swiper-wrapper'); - - const imgViewerThumbsSwiper = imgViewer.querySelector('.js_img_viewer_thumbs_swiper'); - const imgViewerThumbsSwiperWrap = imgViewerThumbsSwiper.querySelector('.js_img_viewer_thumbs_swiper .swiper-wrapper'); - - const introItemBtns = document.querySelectorAll('.js_intro_item_btn'); - - introItemBtns.forEach((btn, i) => { - - btn.addEventListener('click', (e) => { - - e.preventDefault(); - - imgViewer.classList.add('active'); - this.fixBodyPosition(); - - imgViewerSliderSwiperWrap.innerHTML = ''; - imgViewerThumbsSwiperWrap.innerHTML = ''; - imgViewerCaption.textContent = ''; - - - introItemBtns.forEach(btn => { - - imgViewerSliderSwiperWrap.insertAdjacentHTML('beforeend', ` -
- -
` - ); - - imgViewerThumbsSwiperWrap.insertAdjacentHTML('beforeend', ` -
- -
` - ); - - }); - - swiper4.update(); - swiper5.update(); - swiper5.slideTo(i); - imgViewerCaption.textContent = btn.dataset.caption; - - }); - - }); - - swiper5.on('slideChange', function () { - imgViewerCaption.textContent = introItemBtns[swiper5.realIndex].dataset.caption; - }); - - imgViewerCloses.forEach(close => { - - close.addEventListener('click', () => { - - imgViewer.classList.remove('active'); - this.unfixBodyPosition(); - - }); - - }); - - } - - } - - - // куки - setCookies() { - - const cookies = document.querySelector('.js_cookies'); - const cookiesBtn = document.querySelector('.js_cookies_confirm'); - const cookiesTrigger = document.querySelector('.js_btn_cookies'); - - if (cookiesTrigger) { - - cookiesTrigger.addEventListener('click', () => { - cookies.classList.add('active'); - }); - - }; - - if (cookies) { - - cookiesBtn.addEventListener('click', () => { - cookies.classList.remove('active'); - }); - - }; - - } - - - // карта на странице карт; - /* - //setGeneralMap() { - - if (document.querySelector('#general-map')) { - - ymaps.ready(init); // Дождёмся загрузки API и готовности DOM; - - function init() { - - const myMap = new ymaps.Map('general-map', { // Создание экземпляра карты и его привязка к контейнеру с заданным id; - center: [55.752933963675126, 37.52233749962665], // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования; - zoom: 10, - controls: [] // Скрываем элементы управления на карте; - }); - - // Создаём макет содержимого. - const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( - '
$[properties.iconContent]
' - ); - - let collection = new ymaps.GeoObjectCollection(null, { // Создаём коллекцию, в которую будемпомещать метки (что-то типа массива); - // preset: 'islands#yellowIcon' - }); - - let collectionCoords = [ // Создаём массив с координатами (координаты должны располагаться в том же порядке, что и адреса в списке на сайте); - [55.867783219108354, 37.392867499999916], - [55.728043075486504, 37.73937949999994], - [55.72624100423305, 37.476078499999964], - [55.80751105044832, 37.449622999999974], - [55.601783098948836, 37.36700499999998], - [55.86086502152225, 37.540348999999964], - [55.784961528728715, 37.56188599999996], - [55.63910010399773, 37.319407999999996], - [55.55819256767507, 37.55711549999994], - [55.79829252928473, 37.52063549999999], - ]; - - for (let i = 0, l = collectionCoords.length; i < l; i++) { // C помощью цикла добавляем все метки в коллекцию; - collection.add(new ymaps.Placemark(collectionCoords[i])); - collection.get(i).properties.set('iconContent', `${i + 1}`); // Добавляем каждой метке порядковый номер, записываем его в свойство 'iconContent'; - } - - myMap.geoObjects.add(collection); // Добавляем коллекцию с метками на карту; - - collection.options.set('iconLayout', 'default#imageWithContent'); // Необходимо указать данный тип макета; - collection.options.set('iconImageHref', 'images/mark-complex.svg'); // Своё изображение иконки метки; - collection.options.set('iconImageSize', [52, 67]); // Размеры метки; - collection.options.set('iconImageOffset', [-26, -67]); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); - collection.options.set('iconContentOffset', [0, 17]); - collection.options.set('iconContentLayout', MyIconContentLayout); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); - - const pageMapBar = document.querySelector('.js_page_map_bar'); - const pageMapBarBtn = pageMapBar.querySelector('.js_page_map_bar_btn'); - const pageMapBarList = pageMapBar.querySelector('.js_page_map_bar_list'); - const pageMapBarCards = pageMapBar.querySelectorAll('.card-news'); - - const showCard = (i) => { - - pageMapBarCards.forEach((card, k) => { - - card.classList.remove('active'); - - if (i == k) { - card.classList.add('active'); - } - - }); - - }; - - const hidecard = () => { - - pageMapBarCards.forEach(card => { - card.classList.remove('active'); - }); - - } - - let pageMapBarItems; - - pageMapBarBtn.addEventListener('click', () => { - pageMapBar.classList.toggle('active'); - }); - - pageMapBarList.addEventListener('click', (e) => { - - if (e.target.closest('.page-map-bar__item')) { - - pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); - - pageMapBarItems.forEach((item, i) => { - - if (e.target == item && e.target.classList.contains('active')) { - - item.classList.remove('active'); - - hidecard(); - - } else if (e.target == item) { - - pageMapBarItems.forEach(item => { - item.classList.remove('active'); - }); - - item.classList.add('active'); - - let offsetCoords = collection.get(i).geometry.getCoordinates(); - - offsetCoords = [ - offsetCoords[0] - 0.0025, - offsetCoords[1] - ]; - - myMap.setZoom(16); - // myMap.setCenter(collection.get(i).geometry.getCoordinates()); - myMap.setCenter(offsetCoords); - - showCard(i); - - } - - }); - } - - }); - - collection.events.add('click', function (e) { - - for (let i = 0, l = collection.getLength(); i < l; i++) { - - if (e.get('target') == collection.get(i)) { - - pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); - - pageMapBarItems.forEach((item) => { - pageMapBar.classList.add('active'); - item.classList.remove('active'); - }); - - pageMapBarItems[i].classList.add('active'); - - showCard(i); - - } - - } - - }); - - } - - } - - };*/ - - - // аккордеон в футере - setFooterSpoilers() { - - const items = document.querySelectorAll('.js_footer_col'); - - items.forEach(item => { - - const itemTitle = item.querySelector('.js_footer_caption'); - const itemContent = item.querySelector('.js_footer_block'); - - const blockToggle = (block, duration) => { - - if (window.getComputedStyle(block).display == "none" && !block.classList.contains('smooth')) { - - block.style.display = "block"; - - const blockHeight = block.offsetHeight; - - block.style.height = 0; - block.style.overflow = "hidden"; - block.style.transition = `height ${duration}ms ease`; - block.classList.add('smooth'); - block.offsetHeight; - block.style.height = `${blockHeight}px`; - - setTimeout(() => { - - block.classList.remove('smooth'); - block.style.height = ''; - block.style.transition = ''; - block.style.overflow = ''; - - }, duration); - - } else if (!block.classList.contains('smooth')) { - - block.style.height = `${block.offsetHeight}px`; - block.offsetHeight; - block.style.height = 0; - block.style.overflow = "hidden"; - block.style.transition = `height ${duration}ms ease`; - block.classList.add('smooth'); - - setTimeout(() => { - - block.classList.remove('smooth'); - block.style.display = "none"; - block.style.height = ''; - block.style.transition = ''; - block.style.overflow = ''; - - }, duration); - - } - - }; - - itemTitle.addEventListener('click', (e) => { - itemTitle.classList.toggle('active'); - blockToggle(itemContent, 300); - }); - - }); - - } - - - // слайдер с партнёрами; - initPartnerslSlider() { - - const slider = document.querySelector('.partners__swiper'); - - if (slider) { - - let swiper6; - - const initSlider = () => { - - swiper6 = new Swiper(slider, { - // scrollbar: { - // el: '.swiper-scrollbar', - // draggable: true, - // }, - slidesPerView: 0.275, - loop: true, - spaceBetween: 20, - freeMode: true, - allowTouchMove: true, - breakpoints: { - 480: { - slidesPerView: 0.4, - }, - 640: { - slidesPerView: 0.65, - }, - 780: { - slidesPerView: 0.65, - }, - 1024: { - slidesPerView: 0.8, - }, - 1200: { - slidesPerView: 1, - loop: false, - allowTouchMove: false, - } - } - }); - - }; - - initSlider(); - - const updateSlider = () => { - swiper6.destroy(); - initSlider(); - } - - window.addEventListener('resize', () => { - - if (window.innerWidth <= 1200 && slider.dataset.mobile == 'false') { - slider.dataset.mobile = 'true'; - updateSlider(); - } - - if (window.innerWidth > 1200 && slider.dataset.mobile == 'true') { - slider.dataset.mobile = 'false'; - updateSlider(); - } - - }); - - } - - } - -} - - -document.addEventListener('DOMContentLoaded', () => { - - const app = new App(); - app.init(); - -}); diff --git a/public/pug/templates/scripts.pug b/public/pug/templates/scripts.pug index a940c8c..d85015e 100644 --- a/public/pug/templates/scripts.pug +++ b/public/pug/templates/scripts.pug @@ -2,4 +2,4 @@ script(src="https://api-maps.yandex.ru/2.1/?lang=ru_RU") script(src="js/swiper-bundle.min.js") -script(src="js/main_new.js") +script(src="js/main_main.js") diff --git a/resources/views/complex.blade.php b/resources/views/complex.blade.php index 67a8aaa..ceed184 100644 --- a/resources/views/complex.blade.php +++ b/resources/views/complex.blade.php @@ -1,6 +1,7 @@ @extends('layout.site', ['title' => $area->name_area]) @section('custom_js') + @include('js.maps_js') @endsection diff --git a/resources/views/house/post.blade.php b/resources/views/house/post.blade.php index ad569f4..e52b8be 100644 --- a/resources/views/house/post.blade.php +++ b/resources/views/house/post.blade.php @@ -1,4 +1,11 @@ -@extends('layout.site', ['title' => 'Избранное RentTorg']) +@extends('layout.site', ['title' => $house->title]) + +@section('custom_js') + @include('js.maps_js') + +@endsection @section('content')
@@ -30,7 +37,7 @@
-
16 человек интересовались этим объектом за последние 24 ч
+
{{ $count_user->count() }} человек(а) интересовались этим объектом за последние 24 ч
Позвонить diff --git a/resources/views/js/maps_js.blade.php b/resources/views/js/maps_js.blade.php new file mode 100644 index 0000000..2267d09 --- /dev/null +++ b/resources/views/js/maps_js.blade.php @@ -0,0 +1,71 @@ +
$[properties.iconContent]
' + ); + + // Создание макета содержимого хинта. + // Макет создается через фабрику макетов с помощью текстового шаблона. + const HintLayout = ymaps.templateLayoutFactory.createClass("
" + + caption + "
", { + // Определяем метод getShape, который + // будет возвращать размеры макета хинта. + // Это необходимо для того, чтобы хинт автоматически + // сдвигал позицию при выходе за пределы карты. + getShape: function () { + let el = this.getElement(), + result = null; + if (el) { + var firstChild = el.firstChild; + result = new ymaps.shape.Rectangle( + new ymaps.geometry.pixel.Rectangle([ + [0, 0], + [firstChild.offsetWidth, firstChild.offsetHeight] + ]) + ); + } + return result; + } + } + ); + + // метка + const placemark = new ymaps.Placemark(coords, { + // hintContent: caption, + // balloonContent: caption, + iconContent: '1', + // address: caption, + object: caption + }, { + iconLayout: 'default#imageWithContent', + iconImageHref: "{{ asset('images/mark-complex.svg') }}", + iconImageSize: [52, 67], + iconImageOffset: [-26, -67], + iconContentOffset: [0, 17], + iconContentLayout: MyIconContentLayout, + hintLayout: HintLayout + }); + + map.geoObjects.add(placemark); + + } + + } + + } + diff --git a/resources/views/layout/admin.blade.php b/resources/views/layout/admin.blade.php index 351e3eb..202bcfe 100644 --- a/resources/views/layout/admin.blade.php +++ b/resources/views/layout/admin.blade.php @@ -457,7 +457,7 @@
- + @yield('custom_js') diff --git a/resources/views/layout/site.blade.php b/resources/views/layout/site.blade.php index 1303e69..4994470 100644 --- a/resources/views/layout/site.blade.php +++ b/resources/views/layout/site.blade.php @@ -413,7 +413,7 @@ - + @yield('custom_js')