Commit 694201330f9d1eaf2089ff2d570ba2e139c484ba
1 parent
357df98e45
Exists in
master
Добавление координат в карточку офиса и работа с картой
Showing 10 changed files with 1716 additions and 1523 deletions Side-by-side Diff
- app/Http/Controllers/MainController.php
- database/migrations/2023_03_01_073202_create_houses_table.php
- public/js/main.js
- public/js/main_new.js
- public/pug/templates/scripts.pug
- resources/views/admin/houses/form.blade.php
- resources/views/index.blade.php
- resources/views/layout/admin.blade.php
- resources/views/layout/site.blade.php
- resources/views/mapsobj.blade.php
app/Http/Controllers/MainController.php
... | ... | @@ -679,8 +679,11 @@ class MainController extends Controller |
679 | 679 | * Карта объектов |
680 | 680 | */ |
681 | 681 | public function MapsObj(Request $request) { |
682 | + //$houses = House::with('areas'); | |
683 | + //$houses = $houses->orderBy('id')->get(); | |
684 | + $areas = Area::query()->orderBy('id')->get(); | |
682 | 685 | |
683 | - return view('mapsobj'); | |
686 | + return view('mapsobj', compact('areas')); | |
684 | 687 | } |
685 | 688 | |
686 | 689 | /* |
database/migrations/2023_03_01_073202_create_houses_table.php
... | ... | @@ -56,10 +56,11 @@ return new class extends Migration |
56 | 56 | $table->text('description_house')->nullable(true); |
57 | 57 | $table->string('map_coord', 255)->default(''); |
58 | 58 | $table->boolean('best')->default('0'); |
59 | - $table->string('description_2')->default(''); | |
60 | - $table->string('sos_obj')->default('Рабочая'); | |
61 | - $table->string('type_plan')->default('Открытая'); | |
62 | - | |
59 | + $table->string('description_2', 255)->default(''); | |
60 | + $table->string('sos_obj', 255)->default('Рабочая'); | |
61 | + $table->string('type_plan', 255)->default('Открытая'); | |
62 | + $table->string('coord_x', 50)->default('0'); | |
63 | + $table->string('coord_y', 50)->default('0'); | |
63 | 64 | $table->timestamps(); |
64 | 65 | }); |
65 | 66 | } |
public/js/main.js
Changes suppressed. Click to show
... | ... | @@ -1,1507 +0,0 @@ |
1 | -// управляющий класс App с методом init(), в котором собраны все используемые методы с комментариями о том, что конкретно делает каждый метод | |
2 | - | |
3 | -class App { | |
4 | - | |
5 | - constructor() { | |
6 | - this.patternPhone = /^(\+7|7|8)?[\s\-]?\(?[489][0-9]{2}\)?[\s\-]?[0-9]{3}[\s\-]?[0-9]{2}[\s\-]?[0-9]{2}$/; // рег. выражение для поля 'телефон'; | |
7 | - this.patternEmail = /^[a-zA-Z0-9._%+-\.]+@[a-z0-9.-]+\.[a-z]{2,}$/i; // рег. выражение для поля 'электронная почта'; | |
8 | - } | |
9 | - | |
10 | - init() { | |
11 | - | |
12 | - console.log('init'); | |
13 | - | |
14 | - this.stickyHeader(); // липкий хедер; | |
15 | - this.controlBurgerMenu(); // бургер-меню; | |
16 | - this.smoothScroll(); // плавный скролл к якорю (smooth scroll); | |
17 | - this.scrollUp(); // кнопка наверх; | |
18 | - this.addToFavorites(); // добавить в избранное (звёздочка); | |
19 | - this.initTypicalSlider(); // типовые слайдеры; | |
20 | - this.initPartnerslSlider(); // слайдер с партнёрами; | |
21 | - this.controlFilters(); // фильтры на главном экране; | |
22 | - this.controlPopups(); // открытие/закрытие поп-апов; | |
23 | - this.controlContactUsPopup(); // открытие/закрытие поп-апа 'обратный звонок'; | |
24 | - | |
25 | - this.sendForm('.js_popup_feedback_form', '[data-popup="success"]'); // отправка формы в поп-апе обратной связи; | |
26 | - this.sendForm('.js_popup_viewing_form', '[data-popup="success"]'); // отправка формы в поп-апе 'записаться на просмотр'; | |
27 | - this.sendForm('.js_footer_feedback_form', '[data-popup="success"]'); // отправка формы в футере; | |
28 | - this.sendForm('.js_contacts_form', '.js_contacts_success'); // отправка формы на странице контакты; | |
29 | - this.sendForm('.js_popup_sending_form_', '[data-popup="success"]'); | |
30 | - //this.sendOffer(); //отправка предложения по e-mail; | |
31 | - | |
32 | - this.setGeneralMap(); // карта на странице карт; | |
33 | - this.setComplexMap('complex-map', [55.726591050908745, 37.57244549999999], 'ЖК Садовые кварталы'); // карта на странице 'ЖК'; | |
34 | - this.setComplexMap('offer-map', [55.70851106903402, 37.65864349999999], 'Аренда торгового помещения 321,6 м2'); // карта на странице 'Предложение'; | |
35 | - this.setCatalogSorts(); // сортировка на странице 'каталог'; | |
36 | - this.initIntroSlider(); // слайдер на странице жк и на странице предложения; | |
37 | - this.setTabs('.js_offer_side_tab', '.js_offer_side_item'); // табы с планами объекат и этажа на странице предложения; | |
38 | - this.setTabs('.js_offer_side_popup_tab', '.js_offer_side_popup_item'); // табы с планами объекат и этажа в поп-апе на странице предложения; | |
39 | - this.sontrolOfferSidePopup(); // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения; | |
40 | - this.setCustomGallery(); // галлерея; | |
41 | - this.setCookies() // куки; | |
42 | - this.setFooterSpoilers() // аккордеон в футере; | |
43 | - | |
44 | - } | |
45 | - | |
46 | - // фиксация <body> | |
47 | - fixBodyPosition() { | |
48 | - | |
49 | - setTimeout(function () { | |
50 | - // ставим необходимую задержку, чтобы не было «конфликта» в случае, если функция фиксации вызывается сразу после расфиксации (расфиксация отменяет действия расфиксации из-за одновременного действия) | |
51 | - | |
52 | - if (!document.body.hasAttribute('data-body-scroll-fix')) { | |
53 | - | |
54 | - // получаем позицию прокрутки | |
55 | - let scrollPosition = window.pageYOffset || document.documentElement.scrollTop; | |
56 | - | |
57 | - // ставим нужные стили | |
58 | - document.body.setAttribute('data-body-scroll-fix', scrollPosition); // Cтавим атрибут со значением прокрутки | |
59 | - document.body.style.overflow = 'hidden'; | |
60 | - document.body.style.position = 'fixed'; | |
61 | - document.body.style.top = '-' + scrollPosition + 'px'; | |
62 | - document.body.style.left = '0'; | |
63 | - document.body.style.width = '100%'; | |
64 | - | |
65 | - if (window.innerWidth >= 1200) { | |
66 | - document.body.style.paddingRight = '8px'; | |
67 | - } | |
68 | - } | |
69 | - | |
70 | - }, 15); // можно задержку ещё меньше, но работает хорошо именно с этим значением на всех устройствах и браузерах | |
71 | - | |
72 | - } | |
73 | - | |
74 | - | |
75 | - // расфиксация <body> | |
76 | - unfixBodyPosition() { | |
77 | - | |
78 | - if (document.body.hasAttribute('data-body-scroll-fix')) { | |
79 | - | |
80 | - // получаем позицию прокрутки из атрибута | |
81 | - let scrollPosition = document.body.getAttribute('data-body-scroll-fix'); | |
82 | - | |
83 | - // удаляем атрибут | |
84 | - document.body.removeAttribute('data-body-scroll-fix'); | |
85 | - | |
86 | - // удаляем ненужные стили | |
87 | - document.body.style.overflow = ''; | |
88 | - document.body.style.position = ''; | |
89 | - document.body.style.top = ''; | |
90 | - document.body.style.left = ''; | |
91 | - document.body.style.width = ''; | |
92 | - document.body.style.paddingRight = ''; | |
93 | - | |
94 | - // прокручиваем страницу на полученное из атрибута значение | |
95 | - window.scroll(0, scrollPosition); | |
96 | - | |
97 | - } | |
98 | - | |
99 | - } | |
100 | - | |
101 | - | |
102 | - // бургер-меню | |
103 | - controlBurgerMenu() { | |
104 | - | |
105 | - const headerBurger = document.querySelector('.js_header_burger'); | |
106 | - | |
107 | - if (headerBurger) { | |
108 | - | |
109 | - const menu = document.querySelector('.js_menu'); | |
110 | - const menuClose = menu.querySelector('.js_menu_close'); | |
111 | - | |
112 | - headerBurger.addEventListener('click', () => { | |
113 | - menu.classList.add('active'); | |
114 | - this.fixBodyPosition(); | |
115 | - }); | |
116 | - | |
117 | - menu.addEventListener('click', (e) => { | |
118 | - | |
119 | - if (e.target == menu) { | |
120 | - menu.classList.remove('active'); | |
121 | - this.unfixBodyPosition(); | |
122 | - } | |
123 | - | |
124 | - }); | |
125 | - | |
126 | - menuClose.addEventListener('click', () => { | |
127 | - menu.classList.remove('active'); | |
128 | - this.unfixBodyPosition(); | |
129 | - }); | |
130 | - | |
131 | - } | |
132 | - | |
133 | - } | |
134 | - | |
135 | - | |
136 | - // липкий хедер | |
137 | - stickyHeader() { | |
138 | - | |
139 | - const header = document.querySelector('.js_header'); | |
140 | - | |
141 | - if (header) { | |
142 | - | |
143 | - window.addEventListener('scroll', () => { | |
144 | - | |
145 | - if (window.scrollY > 200) { | |
146 | - header.classList.add('fixed'); | |
147 | - } else { | |
148 | - header.classList.remove('fixed'); | |
149 | - } | |
150 | - | |
151 | - }); | |
152 | - | |
153 | - }; | |
154 | - | |
155 | - } | |
156 | - | |
157 | - | |
158 | - // плавный скролл к якорю (smooth scroll) | |
159 | - smoothScroll() { | |
160 | - | |
161 | - const smoothLinks = document.querySelectorAll('.js_smooth_link'); | |
162 | - | |
163 | - if (smoothLinks.length) { | |
164 | - | |
165 | - smoothLinks.forEach(link => { | |
166 | - | |
167 | - link.addEventListener('click', function (e) { | |
168 | - | |
169 | - e.preventDefault(); | |
170 | - | |
171 | - let href = this.getAttribute('href').substring(1); | |
172 | - | |
173 | - const scrollTarget = document.getElementById(href); | |
174 | - | |
175 | - // const topOffset = document.querySelector('.header').offsetHeight; | |
176 | - const topOffset = 0; // если не нужен отступ сверху | |
177 | - const elementPosition = scrollTarget.getBoundingClientRect().top; | |
178 | - const offsetPosition = elementPosition - topOffset; | |
179 | - | |
180 | - window.scrollBy({ | |
181 | - top: offsetPosition, | |
182 | - behavior: 'smooth' | |
183 | - }); | |
184 | - | |
185 | - }); | |
186 | - | |
187 | - }); | |
188 | - | |
189 | - } | |
190 | - | |
191 | - } | |
192 | - | |
193 | - | |
194 | - // кнопка наверх | |
195 | - scrollUp() { | |
196 | - | |
197 | - const toTopBtn = document.querySelector('.js_btn_up'); | |
198 | - | |
199 | - if (toTopBtn) { | |
200 | - | |
201 | - toTopBtn.addEventListener('click', function () { | |
202 | - | |
203 | - window.scrollTo({ | |
204 | - top: 0, | |
205 | - behavior: 'smooth' | |
206 | - }); | |
207 | - | |
208 | - }); | |
209 | - | |
210 | - } | |
211 | - | |
212 | - } | |
213 | - | |
214 | - | |
215 | - // добавить в избранное (звёздочка) | |
216 | - addToFavorites() { | |
217 | - | |
218 | - const cardFavorites = document.querySelectorAll('.js_card_favorites'); | |
219 | - | |
220 | - if (cardFavorites.length) { | |
221 | - | |
222 | - cardFavorites.forEach(item => { | |
223 | - | |
224 | - item.addEventListener('click', (e) => { | |
225 | - e.preventDefault(); | |
226 | - item.classList.toggle('active'); | |
227 | - }); | |
228 | - | |
229 | - }); | |
230 | - | |
231 | - } | |
232 | - | |
233 | - } | |
234 | - | |
235 | - | |
236 | - // типовые слайдеры | |
237 | - initTypicalSlider() { | |
238 | - | |
239 | - const slidersWraps = document.querySelectorAll('.slider__wrap'); | |
240 | - | |
241 | - if (slidersWraps.length) { | |
242 | - | |
243 | - slidersWraps.forEach(wrap => { | |
244 | - | |
245 | - const slider = wrap.querySelector('.swiper'); | |
246 | - const prev = wrap.querySelector('.swiper-button-prev'); | |
247 | - const next = wrap.querySelector('.swiper-button-next'); | |
248 | - const pagination = wrap.querySelector('.swiper-pagination'); | |
249 | - | |
250 | - let swiper1 = new Swiper(slider, { | |
251 | - navigation: { | |
252 | - nextEl: next, | |
253 | - prevEl: prev, | |
254 | - }, | |
255 | - pagination: { | |
256 | - el: pagination, | |
257 | - clickable: true, | |
258 | - }, | |
259 | - slidesPerView: 1, | |
260 | - spaceBetween: 20, | |
261 | - observer: true, | |
262 | - observeParents: true, | |
263 | - observeSlideChildren: true, | |
264 | - breakpoints: { | |
265 | - 480: { | |
266 | - slidesPerView: 1.5, | |
267 | - }, | |
268 | - 640: { | |
269 | - slidesPerView: 2, | |
270 | - }, | |
271 | - 780: { | |
272 | - slidesPerView: 2.5, | |
273 | - }, | |
274 | - 920: { | |
275 | - slidesPerView: 3, | |
276 | - }, | |
277 | - 1024: { | |
278 | - slidesPerView: 3.4 | |
279 | - }, | |
280 | - 1200: { | |
281 | - slidesPerView: 4, | |
282 | - } | |
283 | - } | |
284 | - }); | |
285 | - | |
286 | - }); | |
287 | - | |
288 | - } | |
289 | - | |
290 | - } | |
291 | - | |
292 | - | |
293 | - // метод, делающий число удобночитаемым (добавляет пробел справа через каждые 3 цифры) | |
294 | - prettify(num) { | |
295 | - const withoutSpace = num.replace(/[^\d]/g, ''); //убирает все символы; | |
296 | - return withoutSpace.replace(/(?!^)(?=(?:\d{3})+(?:\.|$))/gm, ' '); //ставит пробелы; | |
297 | - } | |
298 | - | |
299 | - | |
300 | - // фильтры на главном экране | |
301 | - controlFilters() { | |
302 | - | |
303 | - const heroFilters = document.querySelectorAll('.js_hero_filter'); | |
304 | - const heroSearchBtns = document.querySelectorAll('.js_hero_search_btn'); | |
305 | - | |
306 | - if (heroFilters.length) { | |
307 | - | |
308 | - heroFilters.forEach(filter => { | |
309 | - | |
310 | - const heroFilterInput = filter.querySelector('.js_hero_filter_input'); | |
311 | - const heroFilterCurrent = filter.querySelector('.js_hero_filter_current'); | |
312 | - const heroFilterItems = filter.querySelectorAll('.hero-filter__item'); | |
313 | - const heroFilterFields = filter.querySelectorAll('.js_hero_filter_field'); | |
314 | - const heroFilterFrom = filter.querySelector('.js_hero_filter_from'); | |
315 | - const heroFilterTo = filter.querySelector('.js_hero_filter_to'); | |
316 | - const heroFilterReset = filter.querySelector('.js_hero_filter_reset'); | |
317 | - | |
318 | - heroFilterCurrent.addEventListener('click', () => { | |
319 | - | |
320 | - if (filter.classList.contains('active')) { | |
321 | - | |
322 | - filter.classList.remove('active'); | |
323 | - | |
324 | - heroSearchBtns.forEach(btn => { | |
325 | - btn.disabled = false; | |
326 | - }); | |
327 | - | |
328 | - } else { | |
329 | - | |
330 | - heroFilters.forEach(filter => { | |
331 | - filter.classList.remove('active'); | |
332 | - }); | |
333 | - | |
334 | - filter.classList.add('active'); | |
335 | - | |
336 | - heroSearchBtns.forEach(btn => { | |
337 | - btn.disabled = true; | |
338 | - }); | |
339 | - | |
340 | - } | |
341 | - | |
342 | - }); | |
343 | - | |
344 | - if (heroFilterItems.length) { | |
345 | - | |
346 | - heroFilterItems.forEach(item => { | |
347 | - | |
348 | - item.addEventListener('click', () => { | |
349 | - | |
350 | - heroFilterCurrent.textContent = item.textContent; | |
351 | - heroFilterInput.value = item.dataset.val; | |
352 | - filter.classList.remove('active'); | |
353 | - | |
354 | - heroSearchBtns.forEach(btn => { | |
355 | - btn.disabled = false; | |
356 | - }); | |
357 | - | |
358 | - }); | |
359 | - | |
360 | - }); | |
361 | - | |
362 | - } | |
363 | - | |
364 | - if (heroFilterFields.length) { | |
365 | - | |
366 | - const heroFilterMin = heroFilterFrom.dataset.min; | |
367 | - const heroFilterMax = heroFilterTo.dataset.max; | |
368 | - | |
369 | - let heroFilterFromVal; | |
370 | - let heroFilterToVal; | |
371 | - | |
372 | - heroFilterFields.forEach(field => { | |
373 | - | |
374 | - field.addEventListener('input', () => { | |
375 | - | |
376 | - field.value = this.prettify(field.value); | |
377 | - | |
378 | - heroFilterReset.classList.remove('active'); | |
379 | - | |
380 | - heroFilterFields.forEach(field => { | |
381 | - | |
382 | - if (field.value != "") { | |
383 | - heroFilterReset.classList.add('active'); | |
384 | - } | |
385 | - | |
386 | - }); | |
387 | - | |
388 | - }); | |
389 | - | |
390 | - }); | |
391 | - | |
392 | - heroFilterFrom.addEventListener('change', () => { | |
393 | - | |
394 | - heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); | |
395 | - heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); | |
396 | - | |
397 | - if (heroFilterToVal != '' && heroFilterFromVal > heroFilterToVal) { | |
398 | - | |
399 | - heroFilterFrom.value = heroFilterTo.value; | |
400 | - | |
401 | - } else if (heroFilterFromVal < +heroFilterMin) { | |
402 | - | |
403 | - heroFilterFrom.value = this.prettify(heroFilterMin); | |
404 | - | |
405 | - } else if (heroFilterFromVal > +heroFilterMax) { | |
406 | - | |
407 | - heroFilterFrom.value = this.prettify(heroFilterMax); | |
408 | - | |
409 | - } | |
410 | - | |
411 | - }); | |
412 | - | |
413 | - heroFilterTo.addEventListener('change', () => { | |
414 | - | |
415 | - heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); | |
416 | - heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); | |
417 | - | |
418 | - if (heroFilterFromVal != '' && heroFilterToVal < heroFilterFromVal) { | |
419 | - | |
420 | - heroFilterTo.value = heroFilterFrom.value; | |
421 | - | |
422 | - } else if (heroFilterToVal < +heroFilterMin) { | |
423 | - | |
424 | - heroFilterTo.value = this.prettify(heroFilterMax); | |
425 | - | |
426 | - } else if (heroFilterToVal > +heroFilterMax) { | |
427 | - | |
428 | - heroFilterTo.value = this.prettify(heroFilterMax); | |
429 | - | |
430 | - } | |
431 | - | |
432 | - }); | |
433 | - | |
434 | - heroFilterReset.addEventListener('click', () => { | |
435 | - | |
436 | - heroFilterFields.forEach(field => { | |
437 | - field.value = ''; | |
438 | - }); | |
439 | - | |
440 | - heroFilterReset.classList.remove('active'); | |
441 | - | |
442 | - }); | |
443 | - } | |
444 | - | |
445 | - }); | |
446 | - | |
447 | - document.addEventListener('click', (e) => { | |
448 | - | |
449 | - if (!e.target.closest('.js_hero_filter_dropdown') && !e.target.closest('.js_hero_filter_current')) { | |
450 | - | |
451 | - heroFilters.forEach(filter => { | |
452 | - filter.classList.remove('active'); | |
453 | - }); | |
454 | - | |
455 | - heroSearchBtns.forEach(btn => { | |
456 | - btn.disabled = false; | |
457 | - }); | |
458 | - | |
459 | - } | |
460 | - | |
461 | - }); | |
462 | - | |
463 | - } | |
464 | - | |
465 | - } | |
466 | - | |
467 | - | |
468 | - // открытие/закрытие типовых поп-апов | |
469 | - controlPopups() { | |
470 | - | |
471 | - const popupShowBtns = document.querySelectorAll('[data-btn]'); | |
472 | - const popups = document.querySelectorAll('[data-popup]'); | |
473 | - | |
474 | - if (popupShowBtns.length) { | |
475 | - | |
476 | - popupShowBtns.forEach(btn => { | |
477 | - | |
478 | - btn.addEventListener('click', (e) => { | |
479 | - | |
480 | - e.preventDefault(); | |
481 | - | |
482 | - popups.forEach(popup => { | |
483 | - | |
484 | - popup.classList.remove('active'); // если какойто поп-ап открыт, то закрываем его; | |
485 | - this.unfixBodyPosition(); | |
486 | - | |
487 | - if (btn.dataset.btn == popup.dataset.popup) { | |
488 | - popup.classList.add('active'); | |
489 | - this.fixBodyPosition(); | |
490 | - } | |
491 | - | |
492 | - }); | |
493 | - | |
494 | - | |
495 | - }); | |
496 | - | |
497 | - }); | |
498 | - | |
499 | - popups.forEach(popup => { | |
500 | - | |
501 | - const popupCloseBtns = popup.querySelectorAll('.js_popup_close'); | |
502 | - | |
503 | - popupCloseBtns.forEach(btn => { | |
504 | - | |
505 | - btn.addEventListener('click', (e) => { | |
506 | - e.preventDefault(); | |
507 | - popup.classList.remove('active'); | |
508 | - this.unfixBodyPosition(); | |
509 | - }); | |
510 | - | |
511 | - }); | |
512 | - | |
513 | - popup.addEventListener('click', (e) => { | |
514 | - | |
515 | - if (e.target == popup) { | |
516 | - | |
517 | - popup.classList.remove('active'); | |
518 | - this.unfixBodyPosition(); | |
519 | - } | |
520 | - | |
521 | - }); | |
522 | - | |
523 | - }); | |
524 | - | |
525 | - } | |
526 | - } | |
527 | - | |
528 | - | |
529 | - // открытие/закрытие поп-апа 'обратный звонок' | |
530 | - controlContactUsPopup() { | |
531 | - | |
532 | - const contactUsBtn = document.querySelector('.js_btn_contact_us'); | |
533 | - const contactUsPopup = document.querySelector('.js_contact_us'); | |
534 | - | |
535 | - if (contactUsPopup) { | |
536 | - | |
537 | - const contactUsPopupCloseBtns = contactUsPopup.querySelectorAll('.js_contact_us_close'); | |
538 | - | |
539 | - contactUsBtn.addEventListener('click', (e) => { | |
540 | - | |
541 | - e.preventDefault(); | |
542 | - | |
543 | - if (contactUsPopup.classList.contains('active')) { | |
544 | - contactUsPopup.classList.remove('active'); | |
545 | - } else { | |
546 | - contactUsPopup.classList.add('active'); | |
547 | - } | |
548 | - | |
549 | - }); | |
550 | - | |
551 | - contactUsPopupCloseBtns.forEach(btn => { | |
552 | - btn.addEventListener('click', () => { | |
553 | - contactUsPopup.classList.remove('active'); | |
554 | - }); | |
555 | - }); | |
556 | - | |
557 | - | |
558 | - document.addEventListener('click', (e) => { | |
559 | - | |
560 | - if (!e.target.closest('.js_contact_us') && !e.target.closest('.js_btn_contact_us')) { | |
561 | - contactUsPopup.classList.remove('active'); | |
562 | - } | |
563 | - | |
564 | - }); | |
565 | - | |
566 | - } | |
567 | - | |
568 | - } | |
569 | - | |
570 | - | |
571 | - // валидатор форм | |
572 | - validateForm(input) { | |
573 | - | |
574 | - // функция добавления ошибки | |
575 | - const createError = (text) => { | |
576 | - | |
577 | - input.classList.add('error'); | |
578 | - input.classList.remove('no-error'); | |
579 | - | |
580 | - if (input.closest('label').querySelector('span.error')) { | |
581 | - input.closest('label').querySelector('span.error').remove(); | |
582 | - input.closest('label').insertAdjacentHTML('beforeend', `<span class="error">${text}</span>`); | |
583 | - } else { | |
584 | - input.closest('label').insertAdjacentHTML('beforeend', `<span class="error">${text}</span>`); | |
585 | - } | |
586 | - | |
587 | - } | |
588 | - | |
589 | - // функция удаления ошибки | |
590 | - const removeError = () => { | |
591 | - | |
592 | - input.classList.remove('error'); | |
593 | - input.classList.add('no-error'); | |
594 | - | |
595 | - if (input.closest('label').querySelector('span.error')) { | |
596 | - input.closest('label').querySelector('span.error').remove(); | |
597 | - } | |
598 | - | |
599 | - } | |
600 | - | |
601 | - // проверяем на правильность заполнения поля 'Телефон' | |
602 | - if (input.classList.contains('js_input_phone') && input.value == "") { | |
603 | - createError('Заполните, пожалуйста, поле'); | |
604 | - } else if (input.classList.contains('js_input_phone') && input.value.search(this.patternPhone) == 0) { | |
605 | - removeError(); | |
606 | - } else if (input.classList.contains('js_input_phone')) { | |
607 | - createError('Укажите, пожалуйста, корректный телефон'); | |
608 | - } | |
609 | - | |
610 | - // проверяем правильность заполнения поля 'Электронная почта' | |
611 | - if (input.classList.contains('js_input_email') && input.value == "") { | |
612 | - createError('Заполните, пожалуйста, поле'); | |
613 | - } else if (input.classList.contains('js_input_email') && input.value.search(this.patternEmail) == 0) { | |
614 | - removeError(); | |
615 | - } else if (input.classList.contains('js_input_email')) { | |
616 | - createError('Укажите, пожалуйста, корректный e-mail'); | |
617 | - } | |
618 | - | |
619 | - } | |
620 | - | |
621 | - | |
622 | - // отправка форм | |
623 | - sendForm(formEl, success) { | |
624 | - | |
625 | - const form = document.querySelector(formEl); | |
626 | - | |
627 | - if (form) { | |
628 | - | |
629 | - form.addEventListener('submit', async (e) => { | |
630 | - | |
631 | - e.preventDefault(); | |
632 | - | |
633 | - const formInputs = form.querySelectorAll('input'); | |
634 | - const formBtn = form.querySelector('.js_form_btn'); | |
635 | - | |
636 | - formInputs.forEach(input => { // перебираем все инпуты в форме; | |
637 | - | |
638 | - this.validateForm(input); | |
639 | - | |
640 | - input.addEventListener('input', () => { | |
641 | - this.validateForm(input); | |
642 | - }); | |
643 | - | |
644 | - }); | |
645 | - | |
646 | - if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); | |
647 | - | |
648 | - // сюда пишем команды, которые должны сработать после успешной валидации; | |
649 | - | |
650 | - console.log('validate'); | |
651 | - formBtn.classList.add('btn-animate'); | |
652 | - formBtn.disabled = true; | |
653 | - | |
654 | - const formData = new FormData(form); | |
655 | - | |
656 | - console.log(...formData); | |
657 | - | |
658 | - const response = await fetch(e.target.action, { | |
659 | - method: e.target.method, | |
660 | - body: formData | |
661 | - }); | |
662 | - | |
663 | - if (response.ok) { | |
664 | - | |
665 | - setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; | |
666 | - | |
667 | - console.log('Отправлено'); | |
668 | - formBtn.classList.remove('btn-animate'); | |
669 | - formBtn.disabled = false; | |
670 | - if (document.querySelector('[data-popup="feedback"]')) { | |
671 | - document.querySelector('[data-popup="feedback"]').classList.remove('active'); | |
672 | - } | |
673 | - if (document.querySelector('[data-popup="viewing"]')) { | |
674 | - document.querySelector('[data-popup="viewing"]').classList.remove('active'); | |
675 | - } | |
676 | - document.querySelector(success).classList.add('active'); | |
677 | - this.fixBodyPosition(); | |
678 | - form.reset(); | |
679 | - | |
680 | - formInputs.forEach(input => { | |
681 | - input.classList.remove('no-error'); | |
682 | - }); | |
683 | - | |
684 | - }, 2000) | |
685 | - | |
686 | - } else { | |
687 | - formBtn.classList.remove('btn-animate'); | |
688 | - formBtn.disabled = false; | |
689 | - alert('Ошибка'); | |
690 | - } | |
691 | - | |
692 | - } else { | |
693 | - console.log('no-validate'); | |
694 | - form.querySelector('.error').focus(); //фокус к полю с ошибкой; | |
695 | - } | |
696 | - | |
697 | - }); | |
698 | - | |
699 | - } | |
700 | - | |
701 | - } | |
702 | - | |
703 | - //отправка предложения по e-mail | |
704 | - sendOffer() { | |
705 | - | |
706 | - const form = document.querySelector('.js_popup_sending_form'); | |
707 | - | |
708 | - if (form) { | |
709 | - | |
710 | - form.addEventListener('submit', async (e) => { | |
711 | - | |
712 | - e.preventDefault(); | |
713 | - | |
714 | - const formInputs = form.querySelectorAll('input'); | |
715 | - const formBtn = form.querySelector('.js_form_btn'); | |
716 | - | |
717 | - formInputs.forEach(input => { // перебираем все инпуты в форме; | |
718 | - | |
719 | - this.validateForm(input); | |
720 | - | |
721 | - input.addEventListener('input', () => { | |
722 | - this.validateForm(input); | |
723 | - }); | |
724 | - | |
725 | - }); | |
726 | - | |
727 | - if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); | |
728 | - | |
729 | - // сюда пишем команды, которые должны сработать после успешной валидации; | |
730 | - | |
731 | - console.log('validate'); | |
732 | - formBtn.classList.add('btn-animate'); | |
733 | - formBtn.disabled = true; | |
734 | - | |
735 | - const formData = new FormData(form); | |
736 | - | |
737 | - console.log(...formData); | |
738 | - | |
739 | - const response = await fetch(e.target.action, { | |
740 | - method: e.target.method, | |
741 | - body: formData | |
742 | - }); | |
743 | - | |
744 | - if (response.ok) { | |
745 | - | |
746 | - setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; | |
747 | - | |
748 | - console.log('Отправлено'); | |
749 | - formBtn.classList.remove('btn-animate'); | |
750 | - formBtn.disabled = false; | |
751 | - if (document.querySelector('[data-popup="sending"]')) { | |
752 | - document.querySelector('[data-popup="sending"]').classList.remove('active'); | |
753 | - } | |
754 | - this.fixBodyPosition(); | |
755 | - form.reset(); | |
756 | - | |
757 | - formInputs.forEach(input => { | |
758 | - input.classList.remove('no-error'); | |
759 | - }); | |
760 | - | |
761 | - }, 2000) | |
762 | - | |
763 | - } else { | |
764 | - formBtn.classList.remove('btn-animate'); | |
765 | - formBtn.disabled = false; | |
766 | - alert('Ошибка'); | |
767 | - } | |
768 | - | |
769 | - } else { | |
770 | - console.log('no-validate'); | |
771 | - form.querySelector('.error').focus(); //фокус к полю с ошибкой; | |
772 | - } | |
773 | - | |
774 | - }); | |
775 | - | |
776 | - } | |
777 | - | |
778 | - } | |
779 | - | |
780 | - | |
781 | - // карта на странице 'ЖК' | |
782 | - setComplexMap(id, coords, caption) { | |
783 | - | |
784 | - if (document.querySelector('#' + id)) { | |
785 | - | |
786 | - // Дождёмся загрузки API и готовности DOM. | |
787 | - ymaps.ready(init); | |
788 | - | |
789 | - function init() { | |
790 | - const map = new ymaps.Map(id, { | |
791 | - // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования. | |
792 | - center: coords, | |
793 | - zoom: 16, | |
794 | - controls: [] | |
795 | - }); | |
796 | - | |
797 | - // Создаём макет содержимого. | |
798 | - const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( | |
799 | - '<div style="color: #FFFFFF; font-weight: bold;">$[properties.iconContent]</div>' | |
800 | - ); | |
801 | - | |
802 | - // Создание макета содержимого хинта. | |
803 | - // Макет создается через фабрику макетов с помощью текстового шаблона. | |
804 | - const HintLayout = ymaps.templateLayoutFactory.createClass("<div class='my-hint'>" + | |
805 | - "{{ properties.object }}" + "</div>", { | |
806 | - // Определяем метод getShape, который | |
807 | - // будет возвращать размеры макета хинта. | |
808 | - // Это необходимо для того, чтобы хинт автоматически | |
809 | - // сдвигал позицию при выходе за пределы карты. | |
810 | - getShape: function () { | |
811 | - let el = this.getElement(), | |
812 | - result = null; | |
813 | - if (el) { | |
814 | - var firstChild = el.firstChild; | |
815 | - result = new ymaps.shape.Rectangle( | |
816 | - new ymaps.geometry.pixel.Rectangle([ | |
817 | - [0, 0], | |
818 | - [firstChild.offsetWidth, firstChild.offsetHeight] | |
819 | - ]) | |
820 | - ); | |
821 | - } | |
822 | - return result; | |
823 | - } | |
824 | - } | |
825 | - ); | |
826 | - | |
827 | - // метка | |
828 | - const placemark = new ymaps.Placemark(coords, { | |
829 | - // hintContent: caption, | |
830 | - // balloonContent: caption, | |
831 | - iconContent: '1', | |
832 | - // address: caption, | |
833 | - object: caption | |
834 | - }, { | |
835 | - iconLayout: 'default#imageWithContent', | |
836 | - iconImageHref: 'images/mark-complex.svg', | |
837 | - iconImageSize: [52, 67], | |
838 | - iconImageOffset: [-26, -67], | |
839 | - iconContentOffset: [0, 17], | |
840 | - iconContentLayout: MyIconContentLayout, | |
841 | - hintLayout: HintLayout | |
842 | - }); | |
843 | - | |
844 | - map.geoObjects.add(placemark); | |
845 | - | |
846 | - } | |
847 | - | |
848 | - } | |
849 | - | |
850 | - } | |
851 | - | |
852 | - | |
853 | - // фильтры и сортировка на странице 'каталог' | |
854 | - setCatalogSorts() { | |
855 | - | |
856 | - const sortGroups = document.querySelectorAll('.js_sort_group'); | |
857 | - | |
858 | - if (sortGroups.length) { | |
859 | - | |
860 | - sortGroups.forEach(group => { | |
861 | - | |
862 | - const sortGroupInput = group.querySelector('.js_sort_group_input'); | |
863 | - const sortGroupCurrent = group.querySelector('.js_sort_group_current'); | |
864 | - const sortGroupList = group.querySelector('.js_sort_group_list'); | |
865 | - const sortGroupItems = group.querySelectorAll('.js_sort_group_item'); | |
866 | - | |
867 | - const sendRequest = () => { | |
868 | - | |
869 | - const spinner = document.querySelector('.spinner'); // спиннер; | |
870 | - | |
871 | - spinner.classList.add('active'); | |
872 | - document.body.classList.add('overlay'); | |
873 | - /*this.fixBodyPosition(); | |
874 | - | |
875 | - fetch('test.json') | |
876 | - .then(response => response.json()) | |
877 | - .then(data => { | |
878 | - | |
879 | - console.log() | |
880 | - | |
881 | - setTimeout(() => { //имитация ответа сервера | |
882 | - | |
883 | - spinner.classList.remove('active'); | |
884 | - document.body.classList.remove('overlay'); | |
885 | - this.unfixBodyPosition(); | |
886 | - | |
887 | - }, 3000); | |
888 | - | |
889 | - }) | |
890 | - .catch(err => { | |
891 | - console.log(err); | |
892 | - }); | |
893 | - | |
894 | - */ | |
895 | - spinner.classList.remove('active'); | |
896 | - document.body.classList.remove('overlay'); | |
897 | - | |
898 | - | |
899 | - }; | |
900 | - | |
901 | - sortGroupCurrent.addEventListener('click', () => { | |
902 | - | |
903 | - if (group.classList.contains('active')) { | |
904 | - | |
905 | - group.classList.remove('active'); | |
906 | - | |
907 | - } else { | |
908 | - | |
909 | - sortGroups.forEach(group => { | |
910 | - group.classList.remove('active'); | |
911 | - }); | |
912 | - | |
913 | - group.classList.add('active'); | |
914 | - | |
915 | - } | |
916 | - | |
917 | - }); | |
918 | - | |
919 | - sortGroupItems.forEach(item => { | |
920 | - | |
921 | - item.addEventListener('click', () => { | |
922 | - | |
923 | - sortGroupItems.forEach(item => { | |
924 | - item.classList.remove('active'); | |
925 | - }); | |
926 | - | |
927 | - item.classList.add('active'); | |
928 | - sortGroupCurrent.textContent = item.textContent; | |
929 | - sortGroupInput.value = item.dataset.val; | |
930 | - group.classList.remove('active'); | |
931 | - | |
932 | - sendRequest(); | |
933 | - | |
934 | - }); | |
935 | - | |
936 | - }); | |
937 | - | |
938 | - }); | |
939 | - | |
940 | - document.addEventListener('click', (e) => { | |
941 | - | |
942 | - if (!e.target.closest('.js_sort_group_list') && !e.target.closest('.js_sort_group_current')) { | |
943 | - | |
944 | - sortGroups.forEach(group => { | |
945 | - group.classList.remove('active'); | |
946 | - }); | |
947 | - | |
948 | - } | |
949 | - | |
950 | - }); | |
951 | - | |
952 | - } | |
953 | - | |
954 | - } | |
955 | - | |
956 | - | |
957 | - // слайдер на странице жк и на странице предложения | |
958 | - initIntroSlider() { | |
959 | - | |
960 | - let swiper3 = new Swiper('.intro__swiper', { | |
961 | - navigation: { | |
962 | - nextEl: '.swiper-button-next', | |
963 | - prevEl: '.swiper-button-prev', | |
964 | - }, | |
965 | - pagination: { | |
966 | - el: '.swiper-pagination', | |
967 | - clickable: true, | |
968 | - }, | |
969 | - slidesPerView: 1.1, | |
970 | - spaceBetween: 20, | |
971 | - breakpoints: { | |
972 | - 480: { | |
973 | - slidesPerView: 1.5, | |
974 | - }, | |
975 | - 640: { | |
976 | - slidesPerView: 1.75, | |
977 | - }, | |
978 | - 780: { | |
979 | - slidesPerView: 2.15, | |
980 | - }, | |
981 | - 1024: { | |
982 | - slidesPerView: 3.5, | |
983 | - }, | |
984 | - 1200: { | |
985 | - slidesPerView: 1, | |
986 | - } | |
987 | - } | |
988 | - }); | |
989 | - | |
990 | - } | |
991 | - | |
992 | - | |
993 | - // табы на странице предложения | |
994 | - setTabs(tabs, items) { | |
995 | - | |
996 | - const offerSideTabs = document.querySelectorAll(tabs); | |
997 | - const offerSideItems = document.querySelectorAll(items); | |
998 | - | |
999 | - if (offerSideTabs) { | |
1000 | - | |
1001 | - offerSideTabs.forEach(tab => { | |
1002 | - | |
1003 | - tab.addEventListener('click', () => { | |
1004 | - | |
1005 | - offerSideTabs.forEach(tab => { | |
1006 | - tab.classList.remove('active'); | |
1007 | - }); | |
1008 | - | |
1009 | - tab.classList.add('active'); | |
1010 | - | |
1011 | - offerSideItems.forEach(item => { | |
1012 | - | |
1013 | - item.classList.remove('active', 'fade'); | |
1014 | - | |
1015 | - if (tab.dataset.tab == item.dataset.item) { | |
1016 | - item.classList.add('active', 'fade'); | |
1017 | - } | |
1018 | - | |
1019 | - }); | |
1020 | - | |
1021 | - }); | |
1022 | - | |
1023 | - }); | |
1024 | - | |
1025 | - } | |
1026 | - | |
1027 | - } | |
1028 | - | |
1029 | - | |
1030 | - // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения | |
1031 | - sontrolOfferSidePopup() { | |
1032 | - | |
1033 | - const offerSideItems = document.querySelectorAll('.js_offer_side_item'); | |
1034 | - const offerSidePopupTabs = document.querySelectorAll('.js_offer_side_popup_tab'); | |
1035 | - const offerSidePopupItems = document.querySelectorAll('.js_offer_side_popup_item'); | |
1036 | - | |
1037 | - if (offerSideItems) { | |
1038 | - | |
1039 | - offerSideItems.forEach(item => { | |
1040 | - | |
1041 | - const offerSideItemBtn = item.querySelector('.js_offer_side_item_btn'); | |
1042 | - | |
1043 | - offerSideItemBtn.addEventListener('click', (e) => { | |
1044 | - | |
1045 | - e.preventDefault(); | |
1046 | - | |
1047 | - offerSidePopupTabs.forEach(tab => { | |
1048 | - | |
1049 | - tab.classList.remove('active'); | |
1050 | - | |
1051 | - if (item.dataset.item == tab.dataset.tab) { | |
1052 | - tab.classList.add('active'); | |
1053 | - } | |
1054 | - | |
1055 | - }); | |
1056 | - | |
1057 | - offerSidePopupItems.forEach(el => { | |
1058 | - | |
1059 | - el.classList.remove('active', 'fade'); | |
1060 | - | |
1061 | - if (item.dataset.item == el.dataset.item) { | |
1062 | - el.classList.add('active', 'fade'); | |
1063 | - } | |
1064 | - | |
1065 | - }); | |
1066 | - | |
1067 | - }); | |
1068 | - | |
1069 | - }); | |
1070 | - | |
1071 | - } | |
1072 | - | |
1073 | - } | |
1074 | - | |
1075 | - | |
1076 | - // галлерея | |
1077 | - setCustomGallery() { | |
1078 | - | |
1079 | - let swiper4 = new Swiper(".img-viewer__thumbs-swiper", { | |
1080 | - slidesPerView: 3, | |
1081 | - spaceBetween: 8, | |
1082 | - // freeMode: true, | |
1083 | - observer: true, | |
1084 | - observeParents: true, | |
1085 | - observeSlideChildren: true, | |
1086 | - breakpoints: { | |
1087 | - 640: { | |
1088 | - spaceBetween: 10, | |
1089 | - }, | |
1090 | - }, | |
1091 | - }); | |
1092 | - | |
1093 | - let swiper5 = new Swiper(".img-viewer__slider .swiper", { | |
1094 | - navigation: { | |
1095 | - nextEl: ".img-viewer__slider .swiper-button-next", | |
1096 | - prevEl: ".img-viewer__slider .swiper-button-prev", | |
1097 | - }, | |
1098 | - slidesPerView: 1, | |
1099 | - spaceBetween: 20, | |
1100 | - thumbs: { | |
1101 | - swiper: swiper4 | |
1102 | - }, | |
1103 | - observer: true, | |
1104 | - observeParents: true, | |
1105 | - observeSlideChildren: true, | |
1106 | - }); | |
1107 | - | |
1108 | - if (document.querySelector('.js_intro_item_btn')) { | |
1109 | - | |
1110 | - const imgViewer = document.querySelector('.js_img_viewer'); | |
1111 | - const imgViewerCloses = imgViewer.querySelectorAll('.js_img_viewer_close'); | |
1112 | - const imgViewerCaption = imgViewer.querySelector('.js_img_viewer_caption'); | |
1113 | - | |
1114 | - const imgViewerSliderSwiper = imgViewer.querySelector('.js_img_viewer_slider_swiper'); | |
1115 | - const imgViewerSliderSwiperWrap = imgViewerSliderSwiper.querySelector('.js_img_viewer_slider_swiper .swiper-wrapper'); | |
1116 | - | |
1117 | - const imgViewerThumbsSwiper = imgViewer.querySelector('.js_img_viewer_thumbs_swiper'); | |
1118 | - const imgViewerThumbsSwiperWrap = imgViewerThumbsSwiper.querySelector('.js_img_viewer_thumbs_swiper .swiper-wrapper'); | |
1119 | - | |
1120 | - const introItemBtns = document.querySelectorAll('.js_intro_item_btn'); | |
1121 | - | |
1122 | - introItemBtns.forEach((btn, i) => { | |
1123 | - | |
1124 | - btn.addEventListener('click', (e) => { | |
1125 | - | |
1126 | - e.preventDefault(); | |
1127 | - | |
1128 | - imgViewer.classList.add('active'); | |
1129 | - this.fixBodyPosition(); | |
1130 | - | |
1131 | - imgViewerSliderSwiperWrap.innerHTML = ''; | |
1132 | - imgViewerThumbsSwiperWrap.innerHTML = ''; | |
1133 | - imgViewerCaption.textContent = ''; | |
1134 | - | |
1135 | - | |
1136 | - introItemBtns.forEach(btn => { | |
1137 | - | |
1138 | - imgViewerSliderSwiperWrap.insertAdjacentHTML('beforeend', ` | |
1139 | - <div class="swiper-slide"> | |
1140 | - <img src="${btn.getAttribute('href')}" alt=""> | |
1141 | - </div>` | |
1142 | - ); | |
1143 | - | |
1144 | - imgViewerThumbsSwiperWrap.insertAdjacentHTML('beforeend', ` | |
1145 | - <div class="swiper-slide"> | |
1146 | - <img src="${btn.getAttribute('href')}" alt=""> | |
1147 | - </div>` | |
1148 | - ); | |
1149 | - | |
1150 | - }); | |
1151 | - | |
1152 | - swiper4.update(); | |
1153 | - swiper5.update(); | |
1154 | - swiper5.slideTo(i); | |
1155 | - imgViewerCaption.textContent = btn.dataset.caption; | |
1156 | - | |
1157 | - }); | |
1158 | - | |
1159 | - }); | |
1160 | - | |
1161 | - swiper5.on('slideChange', function () { | |
1162 | - imgViewerCaption.textContent = introItemBtns[swiper5.realIndex].dataset.caption; | |
1163 | - }); | |
1164 | - | |
1165 | - imgViewerCloses.forEach(close => { | |
1166 | - | |
1167 | - close.addEventListener('click', () => { | |
1168 | - | |
1169 | - imgViewer.classList.remove('active'); | |
1170 | - this.unfixBodyPosition(); | |
1171 | - | |
1172 | - }); | |
1173 | - | |
1174 | - }); | |
1175 | - | |
1176 | - } | |
1177 | - | |
1178 | - } | |
1179 | - | |
1180 | - | |
1181 | - // куки | |
1182 | - setCookies() { | |
1183 | - | |
1184 | - const cookies = document.querySelector('.js_cookies'); | |
1185 | - const cookiesBtn = document.querySelector('.js_cookies_confirm'); | |
1186 | - const cookiesTrigger = document.querySelector('.js_btn_cookies'); | |
1187 | - | |
1188 | - if (cookiesTrigger) { | |
1189 | - | |
1190 | - cookiesTrigger.addEventListener('click', () => { | |
1191 | - cookies.classList.add('active'); | |
1192 | - }); | |
1193 | - | |
1194 | - }; | |
1195 | - | |
1196 | - if (cookies) { | |
1197 | - | |
1198 | - cookiesBtn.addEventListener('click', () => { | |
1199 | - cookies.classList.remove('active'); | |
1200 | - }); | |
1201 | - | |
1202 | - }; | |
1203 | - | |
1204 | - } | |
1205 | - | |
1206 | - | |
1207 | - // карта на странице карт; | |
1208 | - setGeneralMap() { | |
1209 | - | |
1210 | - if (document.querySelector('#general-map')) { | |
1211 | - | |
1212 | - ymaps.ready(init); // Дождёмся загрузки API и готовности DOM; | |
1213 | - | |
1214 | - function init() { | |
1215 | - | |
1216 | - const myMap = new ymaps.Map('general-map', { // Создание экземпляра карты и его привязка к контейнеру с заданным id; | |
1217 | - center: [55.752933963675126, 37.52233749962665], // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования; | |
1218 | - zoom: 10, | |
1219 | - controls: [] // Скрываем элементы управления на карте; | |
1220 | - }); | |
1221 | - | |
1222 | - // Создаём макет содержимого. | |
1223 | - const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( | |
1224 | - '<div style="color: #FFFFFF; font-weight: bold;">$[properties.iconContent]</div>' | |
1225 | - ); | |
1226 | - | |
1227 | - let collection = new ymaps.GeoObjectCollection(null, { // Создаём коллекцию, в которую будемпомещать метки (что-то типа массива); | |
1228 | - // preset: 'islands#yellowIcon' | |
1229 | - }); | |
1230 | - | |
1231 | - let collectionCoords = [ // Создаём массив с координатами (координаты должны располагаться в том же порядке, что и адреса в списке на сайте); | |
1232 | - [55.867783219108354, 37.392867499999916], | |
1233 | - [55.728043075486504, 37.73937949999994], | |
1234 | - [55.72624100423305, 37.476078499999964], | |
1235 | - [55.80751105044832, 37.449622999999974], | |
1236 | - [55.601783098948836, 37.36700499999998], | |
1237 | - [55.86086502152225, 37.540348999999964], | |
1238 | - [55.784961528728715, 37.56188599999996], | |
1239 | - [55.63910010399773, 37.319407999999996], | |
1240 | - [55.55819256767507, 37.55711549999994], | |
1241 | - [55.79829252928473, 37.52063549999999], | |
1242 | - ]; | |
1243 | - | |
1244 | - for (let i = 0, l = collectionCoords.length; i < l; i++) { // C помощью цикла добавляем все метки в коллекцию; | |
1245 | - collection.add(new ymaps.Placemark(collectionCoords[i])); | |
1246 | - collection.get(i).properties.set('iconContent', `${i + 1}`); // Добавляем каждой метке порядковый номер, записываем его в свойство 'iconContent'; | |
1247 | - } | |
1248 | - | |
1249 | - myMap.geoObjects.add(collection); // Добавляем коллекцию с метками на карту; | |
1250 | - | |
1251 | - collection.options.set('iconLayout', 'default#imageWithContent'); // Необходимо указать данный тип макета; | |
1252 | - collection.options.set('iconImageHref', 'images/mark-complex.svg'); // Своё изображение иконки метки; | |
1253 | - collection.options.set('iconImageSize', [52, 67]); // Размеры метки; | |
1254 | - collection.options.set('iconImageOffset', [-26, -67]); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); | |
1255 | - collection.options.set('iconContentOffset', [0, 17]); | |
1256 | - collection.options.set('iconContentLayout', MyIconContentLayout); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); | |
1257 | - | |
1258 | - const pageMapBar = document.querySelector('.js_page_map_bar'); | |
1259 | - const pageMapBarBtn = pageMapBar.querySelector('.js_page_map_bar_btn'); | |
1260 | - const pageMapBarList = pageMapBar.querySelector('.js_page_map_bar_list'); | |
1261 | - const pageMapBarCards = pageMapBar.querySelectorAll('.card-news'); | |
1262 | - | |
1263 | - const showCard = (i) => { | |
1264 | - | |
1265 | - pageMapBarCards.forEach((card, k) => { | |
1266 | - | |
1267 | - card.classList.remove('active'); | |
1268 | - | |
1269 | - if (i == k) { | |
1270 | - card.classList.add('active'); | |
1271 | - } | |
1272 | - | |
1273 | - }); | |
1274 | - | |
1275 | - }; | |
1276 | - | |
1277 | - const hidecard = () => { | |
1278 | - | |
1279 | - pageMapBarCards.forEach(card => { | |
1280 | - card.classList.remove('active'); | |
1281 | - }); | |
1282 | - | |
1283 | - } | |
1284 | - | |
1285 | - let pageMapBarItems; | |
1286 | - | |
1287 | - pageMapBarBtn.addEventListener('click', () => { | |
1288 | - pageMapBar.classList.toggle('active'); | |
1289 | - }); | |
1290 | - | |
1291 | - pageMapBarList.addEventListener('click', (e) => { | |
1292 | - | |
1293 | - if (e.target.closest('.page-map-bar__item')) { | |
1294 | - | |
1295 | - pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); | |
1296 | - | |
1297 | - pageMapBarItems.forEach((item, i) => { | |
1298 | - | |
1299 | - if (e.target == item && e.target.classList.contains('active')) { | |
1300 | - | |
1301 | - item.classList.remove('active'); | |
1302 | - | |
1303 | - hidecard(); | |
1304 | - | |
1305 | - } else if (e.target == item) { | |
1306 | - | |
1307 | - pageMapBarItems.forEach(item => { | |
1308 | - item.classList.remove('active'); | |
1309 | - }); | |
1310 | - | |
1311 | - item.classList.add('active'); | |
1312 | - | |
1313 | - let offsetCoords = collection.get(i).geometry.getCoordinates(); | |
1314 | - | |
1315 | - offsetCoords = [ | |
1316 | - offsetCoords[0] - 0.0025, | |
1317 | - offsetCoords[1] | |
1318 | - ]; | |
1319 | - | |
1320 | - myMap.setZoom(16); | |
1321 | - // myMap.setCenter(collection.get(i).geometry.getCoordinates()); | |
1322 | - myMap.setCenter(offsetCoords); | |
1323 | - | |
1324 | - showCard(i); | |
1325 | - | |
1326 | - } | |
1327 | - | |
1328 | - }); | |
1329 | - } | |
1330 | - | |
1331 | - }); | |
1332 | - | |
1333 | - collection.events.add('click', function (e) { | |
1334 | - | |
1335 | - for (let i = 0, l = collection.getLength(); i < l; i++) { | |
1336 | - | |
1337 | - if (e.get('target') == collection.get(i)) { | |
1338 | - | |
1339 | - pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); | |
1340 | - | |
1341 | - pageMapBarItems.forEach((item) => { | |
1342 | - pageMapBar.classList.add('active'); | |
1343 | - item.classList.remove('active'); | |
1344 | - }); | |
1345 | - | |
1346 | - pageMapBarItems[i].classList.add('active'); | |
1347 | - | |
1348 | - showCard(i); | |
1349 | - | |
1350 | - } | |
1351 | - | |
1352 | - } | |
1353 | - | |
1354 | - }); | |
1355 | - | |
1356 | - } | |
1357 | - | |
1358 | - } | |
1359 | - | |
1360 | - }; | |
1361 | - | |
1362 | - | |
1363 | - // аккордеон в футере | |
1364 | - setFooterSpoilers() { | |
1365 | - | |
1366 | - const items = document.querySelectorAll('.js_footer_col'); | |
1367 | - | |
1368 | - items.forEach(item => { | |
1369 | - | |
1370 | - const itemTitle = item.querySelector('.js_footer_caption'); | |
1371 | - const itemContent = item.querySelector('.js_footer_block'); | |
1372 | - | |
1373 | - const blockToggle = (block, duration) => { | |
1374 | - | |
1375 | - if (window.getComputedStyle(block).display == "none" && !block.classList.contains('smooth')) { | |
1376 | - | |
1377 | - block.style.display = "block"; | |
1378 | - | |
1379 | - const blockHeight = block.offsetHeight; | |
1380 | - | |
1381 | - block.style.height = 0; | |
1382 | - block.style.overflow = "hidden"; | |
1383 | - block.style.transition = `height ${duration}ms ease`; | |
1384 | - block.classList.add('smooth'); | |
1385 | - block.offsetHeight; | |
1386 | - block.style.height = `${blockHeight}px`; | |
1387 | - | |
1388 | - setTimeout(() => { | |
1389 | - | |
1390 | - block.classList.remove('smooth'); | |
1391 | - block.style.height = ''; | |
1392 | - block.style.transition = ''; | |
1393 | - block.style.overflow = ''; | |
1394 | - | |
1395 | - }, duration); | |
1396 | - | |
1397 | - } else if (!block.classList.contains('smooth')) { | |
1398 | - | |
1399 | - block.style.height = `${block.offsetHeight}px`; | |
1400 | - block.offsetHeight; | |
1401 | - block.style.height = 0; | |
1402 | - block.style.overflow = "hidden"; | |
1403 | - block.style.transition = `height ${duration}ms ease`; | |
1404 | - block.classList.add('smooth'); | |
1405 | - | |
1406 | - setTimeout(() => { | |
1407 | - | |
1408 | - block.classList.remove('smooth'); | |
1409 | - block.style.display = "none"; | |
1410 | - block.style.height = ''; | |
1411 | - block.style.transition = ''; | |
1412 | - block.style.overflow = ''; | |
1413 | - | |
1414 | - }, duration); | |
1415 | - | |
1416 | - } | |
1417 | - | |
1418 | - }; | |
1419 | - | |
1420 | - itemTitle.addEventListener('click', (e) => { | |
1421 | - itemTitle.classList.toggle('active'); | |
1422 | - blockToggle(itemContent, 300); | |
1423 | - }); | |
1424 | - | |
1425 | - }); | |
1426 | - | |
1427 | - } | |
1428 | - | |
1429 | - | |
1430 | - // слайдер с партнёрами; | |
1431 | - initPartnerslSlider() { | |
1432 | - | |
1433 | - const slider = document.querySelector('.partners__swiper'); | |
1434 | - | |
1435 | - if (slider) { | |
1436 | - | |
1437 | - let swiper6; | |
1438 | - | |
1439 | - const initSlider = () => { | |
1440 | - | |
1441 | - swiper6 = new Swiper(slider, { | |
1442 | - // scrollbar: { | |
1443 | - // el: '.swiper-scrollbar', | |
1444 | - // draggable: true, | |
1445 | - // }, | |
1446 | - slidesPerView: 0.275, | |
1447 | - loop: true, | |
1448 | - spaceBetween: 20, | |
1449 | - freeMode: true, | |
1450 | - allowTouchMove: true, | |
1451 | - breakpoints: { | |
1452 | - 480: { | |
1453 | - slidesPerView: 0.4, | |
1454 | - }, | |
1455 | - 640: { | |
1456 | - slidesPerView: 0.65, | |
1457 | - }, | |
1458 | - 780: { | |
1459 | - slidesPerView: 0.65, | |
1460 | - }, | |
1461 | - 1024: { | |
1462 | - slidesPerView: 0.8, | |
1463 | - }, | |
1464 | - 1200: { | |
1465 | - slidesPerView: 1, | |
1466 | - loop: false, | |
1467 | - allowTouchMove: false, | |
1468 | - } | |
1469 | - } | |
1470 | - }); | |
1471 | - | |
1472 | - }; | |
1473 | - | |
1474 | - initSlider(); | |
1475 | - | |
1476 | - const updateSlider = () => { | |
1477 | - swiper6.destroy(); | |
1478 | - initSlider(); | |
1479 | - } | |
1480 | - | |
1481 | - window.addEventListener('resize', () => { | |
1482 | - | |
1483 | - if (window.innerWidth <= 1200 && slider.dataset.mobile == 'false') { | |
1484 | - slider.dataset.mobile = 'true'; | |
1485 | - updateSlider(); | |
1486 | - } | |
1487 | - | |
1488 | - if (window.innerWidth > 1200 && slider.dataset.mobile == 'true') { | |
1489 | - slider.dataset.mobile = 'false'; | |
1490 | - updateSlider(); | |
1491 | - } | |
1492 | - | |
1493 | - }); | |
1494 | - | |
1495 | - } | |
1496 | - | |
1497 | - } | |
1498 | - | |
1499 | -} | |
1500 | - | |
1501 | - | |
1502 | -document.addEventListener('DOMContentLoaded', () => { | |
1503 | - | |
1504 | - const app = new App(); | |
1505 | - app.init(); | |
1506 | - | |
1507 | -}); |
public/js/main_new.js
Changes suppressed. Click to show
... | ... | @@ -0,0 +1,1508 @@ |
1 | +// управляющий класс App с методом init(), в котором собраны все используемые методы с комментариями о том, что конкретно делает каждый метод | |
2 | + | |
3 | +class App { | |
4 | + | |
5 | + constructor() { | |
6 | + this.patternPhone = /^(\+7|7|8)?[\s\-]?\(?[489][0-9]{2}\)?[\s\-]?[0-9]{3}[\s\-]?[0-9]{2}[\s\-]?[0-9]{2}$/; // рег. выражение для поля 'телефон'; | |
7 | + this.patternEmail = /^[a-zA-Z0-9._%+-\.]+@[a-z0-9.-]+\.[a-z]{2,}$/i; // рег. выражение для поля 'электронная почта'; | |
8 | + } | |
9 | + | |
10 | + init() { | |
11 | + | |
12 | + console.log('init'); | |
13 | + | |
14 | + this.stickyHeader(); // липкий хедер; | |
15 | + this.controlBurgerMenu(); // бургер-меню; | |
16 | + this.smoothScroll(); // плавный скролл к якорю (smooth scroll); | |
17 | + this.scrollUp(); // кнопка наверх; | |
18 | + this.addToFavorites(); // добавить в избранное (звёздочка); | |
19 | + this.initTypicalSlider(); // типовые слайдеры; | |
20 | + this.initPartnerslSlider(); // слайдер с партнёрами; | |
21 | + this.controlFilters(); // фильтры на главном экране; | |
22 | + this.controlPopups(); // открытие/закрытие поп-апов; | |
23 | + this.controlContactUsPopup(); // открытие/закрытие поп-апа 'обратный звонок'; | |
24 | + | |
25 | + this.sendForm('.js_popup_feedback_form', '[data-popup="success"]'); // отправка формы в поп-апе обратной связи; | |
26 | + this.sendForm('.js_popup_viewing_form', '[data-popup="success"]'); // отправка формы в поп-апе 'записаться на просмотр'; | |
27 | + this.sendForm('.js_footer_feedback_form', '[data-popup="success"]'); // отправка формы в футере; | |
28 | + this.sendForm('.js_contacts_form', '.js_contacts_success'); // отправка формы на странице контакты; | |
29 | + this.sendForm('.js_popup_sending_form_', '[data-popup="success"]'); | |
30 | + //this.sendOffer(); //отправка предложения по e-mail; | |
31 | + | |
32 | + //this.setGeneralMap(); // карта на странице карт; | |
33 | + this.setComplexMap('complex-map', [55.726591050908745, 37.57244549999999], 'ЖК Садовые кварталы'); // карта на странице 'ЖК'; | |
34 | + this.setComplexMap('offer-map', [55.70851106903402, 37.65864349999999], 'Аренда торгового помещения 321,6 м2'); // карта на странице 'Предложение'; | |
35 | + this.setCatalogSorts(); // сортировка на странице 'каталог'; | |
36 | + this.initIntroSlider(); // слайдер на странице жк и на странице предложения; | |
37 | + this.setTabs('.js_offer_side_tab', '.js_offer_side_item'); // табы с планами объекат и этажа на странице предложения; | |
38 | + this.setTabs('.js_offer_side_popup_tab', '.js_offer_side_popup_item'); // табы с планами объекат и этажа в поп-апе на странице предложения; | |
39 | + this.sontrolOfferSidePopup(); // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения; | |
40 | + this.setCustomGallery(); // галлерея; | |
41 | + this.setCookies() // куки; | |
42 | + this.setFooterSpoilers() // аккордеон в футере; | |
43 | + | |
44 | + } | |
45 | + | |
46 | + // фиксация <body> | |
47 | + fixBodyPosition() { | |
48 | + | |
49 | + setTimeout(function () { | |
50 | + // ставим необходимую задержку, чтобы не было «конфликта» в случае, если функция фиксации вызывается сразу после расфиксации (расфиксация отменяет действия расфиксации из-за одновременного действия) | |
51 | + | |
52 | + if (!document.body.hasAttribute('data-body-scroll-fix')) { | |
53 | + | |
54 | + // получаем позицию прокрутки | |
55 | + let scrollPosition = window.pageYOffset || document.documentElement.scrollTop; | |
56 | + | |
57 | + // ставим нужные стили | |
58 | + document.body.setAttribute('data-body-scroll-fix', scrollPosition); // Cтавим атрибут со значением прокрутки | |
59 | + document.body.style.overflow = 'hidden'; | |
60 | + document.body.style.position = 'fixed'; | |
61 | + document.body.style.top = '-' + scrollPosition + 'px'; | |
62 | + document.body.style.left = '0'; | |
63 | + document.body.style.width = '100%'; | |
64 | + | |
65 | + if (window.innerWidth >= 1200) { | |
66 | + document.body.style.paddingRight = '8px'; | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + }, 15); // можно задержку ещё меньше, но работает хорошо именно с этим значением на всех устройствах и браузерах | |
71 | + | |
72 | + } | |
73 | + | |
74 | + | |
75 | + // расфиксация <body> | |
76 | + unfixBodyPosition() { | |
77 | + | |
78 | + if (document.body.hasAttribute('data-body-scroll-fix')) { | |
79 | + | |
80 | + // получаем позицию прокрутки из атрибута | |
81 | + let scrollPosition = document.body.getAttribute('data-body-scroll-fix'); | |
82 | + | |
83 | + // удаляем атрибут | |
84 | + document.body.removeAttribute('data-body-scroll-fix'); | |
85 | + | |
86 | + // удаляем ненужные стили | |
87 | + document.body.style.overflow = ''; | |
88 | + document.body.style.position = ''; | |
89 | + document.body.style.top = ''; | |
90 | + document.body.style.left = ''; | |
91 | + document.body.style.width = ''; | |
92 | + document.body.style.paddingRight = ''; | |
93 | + | |
94 | + // прокручиваем страницу на полученное из атрибута значение | |
95 | + window.scroll(0, scrollPosition); | |
96 | + | |
97 | + } | |
98 | + | |
99 | + } | |
100 | + | |
101 | + | |
102 | + // бургер-меню | |
103 | + controlBurgerMenu() { | |
104 | + | |
105 | + const headerBurger = document.querySelector('.js_header_burger'); | |
106 | + | |
107 | + if (headerBurger) { | |
108 | + | |
109 | + const menu = document.querySelector('.js_menu'); | |
110 | + const menuClose = menu.querySelector('.js_menu_close'); | |
111 | + | |
112 | + headerBurger.addEventListener('click', () => { | |
113 | + menu.classList.add('active'); | |
114 | + this.fixBodyPosition(); | |
115 | + }); | |
116 | + | |
117 | + menu.addEventListener('click', (e) => { | |
118 | + | |
119 | + if (e.target == menu) { | |
120 | + menu.classList.remove('active'); | |
121 | + this.unfixBodyPosition(); | |
122 | + } | |
123 | + | |
124 | + }); | |
125 | + | |
126 | + menuClose.addEventListener('click', () => { | |
127 | + menu.classList.remove('active'); | |
128 | + this.unfixBodyPosition(); | |
129 | + }); | |
130 | + | |
131 | + } | |
132 | + | |
133 | + } | |
134 | + | |
135 | + | |
136 | + // липкий хедер | |
137 | + stickyHeader() { | |
138 | + | |
139 | + const header = document.querySelector('.js_header'); | |
140 | + | |
141 | + if (header) { | |
142 | + | |
143 | + window.addEventListener('scroll', () => { | |
144 | + | |
145 | + if (window.scrollY > 200) { | |
146 | + header.classList.add('fixed'); | |
147 | + } else { | |
148 | + header.classList.remove('fixed'); | |
149 | + } | |
150 | + | |
151 | + }); | |
152 | + | |
153 | + }; | |
154 | + | |
155 | + } | |
156 | + | |
157 | + | |
158 | + // плавный скролл к якорю (smooth scroll) | |
159 | + smoothScroll() { | |
160 | + | |
161 | + const smoothLinks = document.querySelectorAll('.js_smooth_link'); | |
162 | + | |
163 | + if (smoothLinks.length) { | |
164 | + | |
165 | + smoothLinks.forEach(link => { | |
166 | + | |
167 | + link.addEventListener('click', function (e) { | |
168 | + | |
169 | + e.preventDefault(); | |
170 | + | |
171 | + let href = this.getAttribute('href').substring(1); | |
172 | + | |
173 | + const scrollTarget = document.getElementById(href); | |
174 | + | |
175 | + // const topOffset = document.querySelector('.header').offsetHeight; | |
176 | + const topOffset = 0; // если не нужен отступ сверху | |
177 | + const elementPosition = scrollTarget.getBoundingClientRect().top; | |
178 | + const offsetPosition = elementPosition - topOffset; | |
179 | + | |
180 | + window.scrollBy({ | |
181 | + top: offsetPosition, | |
182 | + behavior: 'smooth' | |
183 | + }); | |
184 | + | |
185 | + }); | |
186 | + | |
187 | + }); | |
188 | + | |
189 | + } | |
190 | + | |
191 | + } | |
192 | + | |
193 | + | |
194 | + // кнопка наверх | |
195 | + scrollUp() { | |
196 | + | |
197 | + const toTopBtn = document.querySelector('.js_btn_up'); | |
198 | + | |
199 | + if (toTopBtn) { | |
200 | + | |
201 | + toTopBtn.addEventListener('click', function () { | |
202 | + | |
203 | + window.scrollTo({ | |
204 | + top: 0, | |
205 | + behavior: 'smooth' | |
206 | + }); | |
207 | + | |
208 | + }); | |
209 | + | |
210 | + } | |
211 | + | |
212 | + } | |
213 | + | |
214 | + | |
215 | + // добавить в избранное (звёздочка) | |
216 | + addToFavorites() { | |
217 | + | |
218 | + const cardFavorites = document.querySelectorAll('.js_card_favorites'); | |
219 | + | |
220 | + if (cardFavorites.length) { | |
221 | + | |
222 | + cardFavorites.forEach(item => { | |
223 | + | |
224 | + item.addEventListener('click', (e) => { | |
225 | + e.preventDefault(); | |
226 | + item.classList.toggle('active'); | |
227 | + }); | |
228 | + | |
229 | + }); | |
230 | + | |
231 | + } | |
232 | + | |
233 | + } | |
234 | + | |
235 | + | |
236 | + // типовые слайдеры | |
237 | + initTypicalSlider() { | |
238 | + | |
239 | + const slidersWraps = document.querySelectorAll('.slider__wrap'); | |
240 | + | |
241 | + if (slidersWraps.length) { | |
242 | + | |
243 | + slidersWraps.forEach(wrap => { | |
244 | + | |
245 | + const slider = wrap.querySelector('.swiper'); | |
246 | + const prev = wrap.querySelector('.swiper-button-prev'); | |
247 | + const next = wrap.querySelector('.swiper-button-next'); | |
248 | + const pagination = wrap.querySelector('.swiper-pagination'); | |
249 | + | |
250 | + let swiper1 = new Swiper(slider, { | |
251 | + navigation: { | |
252 | + nextEl: next, | |
253 | + prevEl: prev, | |
254 | + }, | |
255 | + pagination: { | |
256 | + el: pagination, | |
257 | + clickable: true, | |
258 | + }, | |
259 | + slidesPerView: 1, | |
260 | + spaceBetween: 20, | |
261 | + observer: true, | |
262 | + observeParents: true, | |
263 | + observeSlideChildren: true, | |
264 | + breakpoints: { | |
265 | + 480: { | |
266 | + slidesPerView: 1.5, | |
267 | + }, | |
268 | + 640: { | |
269 | + slidesPerView: 2, | |
270 | + }, | |
271 | + 780: { | |
272 | + slidesPerView: 2.5, | |
273 | + }, | |
274 | + 920: { | |
275 | + slidesPerView: 3, | |
276 | + }, | |
277 | + 1024: { | |
278 | + slidesPerView: 3.4 | |
279 | + }, | |
280 | + 1200: { | |
281 | + slidesPerView: 4, | |
282 | + } | |
283 | + } | |
284 | + }); | |
285 | + | |
286 | + }); | |
287 | + | |
288 | + } | |
289 | + | |
290 | + } | |
291 | + | |
292 | + | |
293 | + // метод, делающий число удобночитаемым (добавляет пробел справа через каждые 3 цифры) | |
294 | + prettify(num) { | |
295 | + const withoutSpace = num.replace(/[^\d]/g, ''); //убирает все символы; | |
296 | + return withoutSpace.replace(/(?!^)(?=(?:\d{3})+(?:\.|$))/gm, ' '); //ставит пробелы; | |
297 | + } | |
298 | + | |
299 | + | |
300 | + // фильтры на главном экране | |
301 | + controlFilters() { | |
302 | + | |
303 | + const heroFilters = document.querySelectorAll('.js_hero_filter'); | |
304 | + const heroSearchBtns = document.querySelectorAll('.js_hero_search_btn'); | |
305 | + | |
306 | + if (heroFilters.length) { | |
307 | + | |
308 | + heroFilters.forEach(filter => { | |
309 | + | |
310 | + const heroFilterInput = filter.querySelector('.js_hero_filter_input'); | |
311 | + const heroFilterCurrent = filter.querySelector('.js_hero_filter_current'); | |
312 | + const heroFilterItems = filter.querySelectorAll('.hero-filter__item'); | |
313 | + const heroFilterFields = filter.querySelectorAll('.js_hero_filter_field'); | |
314 | + const heroFilterFrom = filter.querySelector('.js_hero_filter_from'); | |
315 | + const heroFilterTo = filter.querySelector('.js_hero_filter_to'); | |
316 | + const heroFilterReset = filter.querySelector('.js_hero_filter_reset'); | |
317 | + | |
318 | + heroFilterCurrent.addEventListener('click', () => { | |
319 | + | |
320 | + if (filter.classList.contains('active')) { | |
321 | + | |
322 | + filter.classList.remove('active'); | |
323 | + | |
324 | + heroSearchBtns.forEach(btn => { | |
325 | + btn.disabled = false; | |
326 | + }); | |
327 | + | |
328 | + } else { | |
329 | + | |
330 | + heroFilters.forEach(filter => { | |
331 | + filter.classList.remove('active'); | |
332 | + }); | |
333 | + | |
334 | + filter.classList.add('active'); | |
335 | + | |
336 | + heroSearchBtns.forEach(btn => { | |
337 | + btn.disabled = true; | |
338 | + }); | |
339 | + | |
340 | + } | |
341 | + | |
342 | + }); | |
343 | + | |
344 | + if (heroFilterItems.length) { | |
345 | + | |
346 | + heroFilterItems.forEach(item => { | |
347 | + | |
348 | + item.addEventListener('click', () => { | |
349 | + | |
350 | + heroFilterCurrent.textContent = item.textContent; | |
351 | + heroFilterInput.value = item.dataset.val; | |
352 | + filter.classList.remove('active'); | |
353 | + | |
354 | + heroSearchBtns.forEach(btn => { | |
355 | + btn.disabled = false; | |
356 | + }); | |
357 | + | |
358 | + }); | |
359 | + | |
360 | + }); | |
361 | + | |
362 | + } | |
363 | + | |
364 | + if (heroFilterFields.length) { | |
365 | + | |
366 | + const heroFilterMin = heroFilterFrom.dataset.min; | |
367 | + const heroFilterMax = heroFilterTo.dataset.max; | |
368 | + | |
369 | + let heroFilterFromVal; | |
370 | + let heroFilterToVal; | |
371 | + | |
372 | + heroFilterFields.forEach(field => { | |
373 | + | |
374 | + field.addEventListener('input', () => { | |
375 | + | |
376 | + field.value = this.prettify(field.value); | |
377 | + | |
378 | + heroFilterReset.classList.remove('active'); | |
379 | + | |
380 | + heroFilterFields.forEach(field => { | |
381 | + | |
382 | + if (field.value != "") { | |
383 | + heroFilterReset.classList.add('active'); | |
384 | + } | |
385 | + | |
386 | + }); | |
387 | + | |
388 | + }); | |
389 | + | |
390 | + }); | |
391 | + | |
392 | + heroFilterFrom.addEventListener('change', () => { | |
393 | + | |
394 | + heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); | |
395 | + heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); | |
396 | + | |
397 | + if (heroFilterToVal != '' && heroFilterFromVal > heroFilterToVal) { | |
398 | + | |
399 | + heroFilterFrom.value = heroFilterTo.value; | |
400 | + | |
401 | + } else if (heroFilterFromVal < +heroFilterMin) { | |
402 | + | |
403 | + heroFilterFrom.value = this.prettify(heroFilterMin); | |
404 | + | |
405 | + } else if (heroFilterFromVal > +heroFilterMax) { | |
406 | + | |
407 | + heroFilterFrom.value = this.prettify(heroFilterMax); | |
408 | + | |
409 | + } | |
410 | + | |
411 | + }); | |
412 | + | |
413 | + heroFilterTo.addEventListener('change', () => { | |
414 | + | |
415 | + heroFilterFromVal = +heroFilterFrom.value.replace(/\s/g, ''); | |
416 | + heroFilterToVal = +heroFilterTo.value.replace(/\s/g, ''); | |
417 | + | |
418 | + if (heroFilterFromVal != '' && heroFilterToVal < heroFilterFromVal) { | |
419 | + | |
420 | + heroFilterTo.value = heroFilterFrom.value; | |
421 | + | |
422 | + } else if (heroFilterToVal < +heroFilterMin) { | |
423 | + | |
424 | + heroFilterTo.value = this.prettify(heroFilterMax); | |
425 | + | |
426 | + } else if (heroFilterToVal > +heroFilterMax) { | |
427 | + | |
428 | + heroFilterTo.value = this.prettify(heroFilterMax); | |
429 | + | |
430 | + } | |
431 | + | |
432 | + }); | |
433 | + | |
434 | + heroFilterReset.addEventListener('click', () => { | |
435 | + | |
436 | + heroFilterFields.forEach(field => { | |
437 | + field.value = ''; | |
438 | + }); | |
439 | + | |
440 | + heroFilterReset.classList.remove('active'); | |
441 | + | |
442 | + }); | |
443 | + } | |
444 | + | |
445 | + }); | |
446 | + | |
447 | + document.addEventListener('click', (e) => { | |
448 | + | |
449 | + if (!e.target.closest('.js_hero_filter_dropdown') && !e.target.closest('.js_hero_filter_current')) { | |
450 | + | |
451 | + heroFilters.forEach(filter => { | |
452 | + filter.classList.remove('active'); | |
453 | + }); | |
454 | + | |
455 | + heroSearchBtns.forEach(btn => { | |
456 | + btn.disabled = false; | |
457 | + }); | |
458 | + | |
459 | + } | |
460 | + | |
461 | + }); | |
462 | + | |
463 | + } | |
464 | + | |
465 | + } | |
466 | + | |
467 | + | |
468 | + // открытие/закрытие типовых поп-апов | |
469 | + controlPopups() { | |
470 | + | |
471 | + const popupShowBtns = document.querySelectorAll('[data-btn]'); | |
472 | + const popups = document.querySelectorAll('[data-popup]'); | |
473 | + | |
474 | + if (popupShowBtns.length) { | |
475 | + | |
476 | + popupShowBtns.forEach(btn => { | |
477 | + | |
478 | + btn.addEventListener('click', (e) => { | |
479 | + | |
480 | + e.preventDefault(); | |
481 | + | |
482 | + popups.forEach(popup => { | |
483 | + | |
484 | + popup.classList.remove('active'); // если какойто поп-ап открыт, то закрываем его; | |
485 | + this.unfixBodyPosition(); | |
486 | + | |
487 | + if (btn.dataset.btn == popup.dataset.popup) { | |
488 | + popup.classList.add('active'); | |
489 | + this.fixBodyPosition(); | |
490 | + } | |
491 | + | |
492 | + }); | |
493 | + | |
494 | + | |
495 | + }); | |
496 | + | |
497 | + }); | |
498 | + | |
499 | + popups.forEach(popup => { | |
500 | + | |
501 | + const popupCloseBtns = popup.querySelectorAll('.js_popup_close'); | |
502 | + | |
503 | + popupCloseBtns.forEach(btn => { | |
504 | + | |
505 | + btn.addEventListener('click', (e) => { | |
506 | + e.preventDefault(); | |
507 | + popup.classList.remove('active'); | |
508 | + this.unfixBodyPosition(); | |
509 | + }); | |
510 | + | |
511 | + }); | |
512 | + | |
513 | + popup.addEventListener('click', (e) => { | |
514 | + | |
515 | + if (e.target == popup) { | |
516 | + | |
517 | + popup.classList.remove('active'); | |
518 | + this.unfixBodyPosition(); | |
519 | + } | |
520 | + | |
521 | + }); | |
522 | + | |
523 | + }); | |
524 | + | |
525 | + } | |
526 | + } | |
527 | + | |
528 | + | |
529 | + // открытие/закрытие поп-апа 'обратный звонок' | |
530 | + controlContactUsPopup() { | |
531 | + | |
532 | + const contactUsBtn = document.querySelector('.js_btn_contact_us'); | |
533 | + const contactUsPopup = document.querySelector('.js_contact_us'); | |
534 | + | |
535 | + if (contactUsPopup) { | |
536 | + | |
537 | + const contactUsPopupCloseBtns = contactUsPopup.querySelectorAll('.js_contact_us_close'); | |
538 | + | |
539 | + contactUsBtn.addEventListener('click', (e) => { | |
540 | + | |
541 | + e.preventDefault(); | |
542 | + | |
543 | + if (contactUsPopup.classList.contains('active')) { | |
544 | + contactUsPopup.classList.remove('active'); | |
545 | + } else { | |
546 | + contactUsPopup.classList.add('active'); | |
547 | + } | |
548 | + | |
549 | + }); | |
550 | + | |
551 | + contactUsPopupCloseBtns.forEach(btn => { | |
552 | + btn.addEventListener('click', () => { | |
553 | + contactUsPopup.classList.remove('active'); | |
554 | + }); | |
555 | + }); | |
556 | + | |
557 | + | |
558 | + document.addEventListener('click', (e) => { | |
559 | + | |
560 | + if (!e.target.closest('.js_contact_us') && !e.target.closest('.js_btn_contact_us')) { | |
561 | + contactUsPopup.classList.remove('active'); | |
562 | + } | |
563 | + | |
564 | + }); | |
565 | + | |
566 | + } | |
567 | + | |
568 | + } | |
569 | + | |
570 | + | |
571 | + // валидатор форм | |
572 | + validateForm(input) { | |
573 | + | |
574 | + // функция добавления ошибки | |
575 | + const createError = (text) => { | |
576 | + | |
577 | + input.classList.add('error'); | |
578 | + input.classList.remove('no-error'); | |
579 | + | |
580 | + if (input.closest('label').querySelector('span.error')) { | |
581 | + input.closest('label').querySelector('span.error').remove(); | |
582 | + input.closest('label').insertAdjacentHTML('beforeend', `<span class="error">${text}</span>`); | |
583 | + } else { | |
584 | + input.closest('label').insertAdjacentHTML('beforeend', `<span class="error">${text}</span>`); | |
585 | + } | |
586 | + | |
587 | + } | |
588 | + | |
589 | + // функция удаления ошибки | |
590 | + const removeError = () => { | |
591 | + | |
592 | + input.classList.remove('error'); | |
593 | + input.classList.add('no-error'); | |
594 | + | |
595 | + if (input.closest('label').querySelector('span.error')) { | |
596 | + input.closest('label').querySelector('span.error').remove(); | |
597 | + } | |
598 | + | |
599 | + } | |
600 | + | |
601 | + // проверяем на правильность заполнения поля 'Телефон' | |
602 | + if (input.classList.contains('js_input_phone') && input.value == "") { | |
603 | + createError('Заполните, пожалуйста, поле'); | |
604 | + } else if (input.classList.contains('js_input_phone') && input.value.search(this.patternPhone) == 0) { | |
605 | + removeError(); | |
606 | + } else if (input.classList.contains('js_input_phone')) { | |
607 | + createError('Укажите, пожалуйста, корректный телефон'); | |
608 | + } | |
609 | + | |
610 | + // проверяем правильность заполнения поля 'Электронная почта' | |
611 | + if (input.classList.contains('js_input_email') && input.value == "") { | |
612 | + createError('Заполните, пожалуйста, поле'); | |
613 | + } else if (input.classList.contains('js_input_email') && input.value.search(this.patternEmail) == 0) { | |
614 | + removeError(); | |
615 | + } else if (input.classList.contains('js_input_email')) { | |
616 | + createError('Укажите, пожалуйста, корректный e-mail'); | |
617 | + } | |
618 | + | |
619 | + } | |
620 | + | |
621 | + | |
622 | + // отправка форм | |
623 | + sendForm(formEl, success) { | |
624 | + | |
625 | + const form = document.querySelector(formEl); | |
626 | + | |
627 | + if (form) { | |
628 | + | |
629 | + form.addEventListener('submit', async (e) => { | |
630 | + | |
631 | + e.preventDefault(); | |
632 | + | |
633 | + const formInputs = form.querySelectorAll('input'); | |
634 | + const formBtn = form.querySelector('.js_form_btn'); | |
635 | + | |
636 | + formInputs.forEach(input => { // перебираем все инпуты в форме; | |
637 | + | |
638 | + this.validateForm(input); | |
639 | + | |
640 | + input.addEventListener('input', () => { | |
641 | + this.validateForm(input); | |
642 | + }); | |
643 | + | |
644 | + }); | |
645 | + | |
646 | + if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); | |
647 | + | |
648 | + // сюда пишем команды, которые должны сработать после успешной валидации; | |
649 | + | |
650 | + console.log('validate'); | |
651 | + formBtn.classList.add('btn-animate'); | |
652 | + formBtn.disabled = true; | |
653 | + | |
654 | + const formData = new FormData(form); | |
655 | + | |
656 | + console.log(...formData); | |
657 | + | |
658 | + const response = await fetch(e.target.action, { | |
659 | + method: e.target.method, | |
660 | + body: formData | |
661 | + }); | |
662 | + | |
663 | + if (response.ok) { | |
664 | + | |
665 | + setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; | |
666 | + | |
667 | + console.log('Отправлено'); | |
668 | + formBtn.classList.remove('btn-animate'); | |
669 | + formBtn.disabled = false; | |
670 | + if (document.querySelector('[data-popup="feedback"]')) { | |
671 | + document.querySelector('[data-popup="feedback"]').classList.remove('active'); | |
672 | + } | |
673 | + if (document.querySelector('[data-popup="viewing"]')) { | |
674 | + document.querySelector('[data-popup="viewing"]').classList.remove('active'); | |
675 | + } | |
676 | + document.querySelector(success).classList.add('active'); | |
677 | + this.fixBodyPosition(); | |
678 | + form.reset(); | |
679 | + | |
680 | + formInputs.forEach(input => { | |
681 | + input.classList.remove('no-error'); | |
682 | + }); | |
683 | + | |
684 | + }, 2000) | |
685 | + | |
686 | + } else { | |
687 | + formBtn.classList.remove('btn-animate'); | |
688 | + formBtn.disabled = false; | |
689 | + alert('Ошибка'); | |
690 | + } | |
691 | + | |
692 | + } else { | |
693 | + console.log('no-validate'); | |
694 | + form.querySelector('.error').focus(); //фокус к полю с ошибкой; | |
695 | + } | |
696 | + | |
697 | + }); | |
698 | + | |
699 | + } | |
700 | + | |
701 | + } | |
702 | + | |
703 | + //отправка предложения по e-mail | |
704 | + sendOffer() { | |
705 | + | |
706 | + const form = document.querySelector('.js_popup_sending_form'); | |
707 | + | |
708 | + if (form) { | |
709 | + | |
710 | + form.addEventListener('submit', async (e) => { | |
711 | + | |
712 | + e.preventDefault(); | |
713 | + | |
714 | + const formInputs = form.querySelectorAll('input'); | |
715 | + const formBtn = form.querySelector('.js_form_btn'); | |
716 | + | |
717 | + formInputs.forEach(input => { // перебираем все инпуты в форме; | |
718 | + | |
719 | + this.validateForm(input); | |
720 | + | |
721 | + input.addEventListener('input', () => { | |
722 | + this.validateForm(input); | |
723 | + }); | |
724 | + | |
725 | + }); | |
726 | + | |
727 | + if (!form.querySelector('.error')) { //проверяем, чтоб все инпуты прошли валидацию (чтоб не было в форме ни одного элемента с класссом error); | |
728 | + | |
729 | + // сюда пишем команды, которые должны сработать после успешной валидации; | |
730 | + | |
731 | + console.log('validate'); | |
732 | + formBtn.classList.add('btn-animate'); | |
733 | + formBtn.disabled = true; | |
734 | + | |
735 | + const formData = new FormData(form); | |
736 | + | |
737 | + console.log(...formData); | |
738 | + | |
739 | + const response = await fetch(e.target.action, { | |
740 | + method: e.target.method, | |
741 | + body: formData | |
742 | + }); | |
743 | + | |
744 | + if (response.ok) { | |
745 | + | |
746 | + setTimeout(() => { // имитация отправки, когда отправка будет настроена, нужно достать всё из setTimeout() и удалить его; | |
747 | + | |
748 | + console.log('Отправлено'); | |
749 | + formBtn.classList.remove('btn-animate'); | |
750 | + formBtn.disabled = false; | |
751 | + if (document.querySelector('[data-popup="sending"]')) { | |
752 | + document.querySelector('[data-popup="sending"]').classList.remove('active'); | |
753 | + } | |
754 | + this.fixBodyPosition(); | |
755 | + form.reset(); | |
756 | + | |
757 | + formInputs.forEach(input => { | |
758 | + input.classList.remove('no-error'); | |
759 | + }); | |
760 | + | |
761 | + }, 2000) | |
762 | + | |
763 | + } else { | |
764 | + formBtn.classList.remove('btn-animate'); | |
765 | + formBtn.disabled = false; | |
766 | + alert('Ошибка'); | |
767 | + } | |
768 | + | |
769 | + } else { | |
770 | + console.log('no-validate'); | |
771 | + form.querySelector('.error').focus(); //фокус к полю с ошибкой; | |
772 | + } | |
773 | + | |
774 | + }); | |
775 | + | |
776 | + } | |
777 | + | |
778 | + } | |
779 | + | |
780 | + | |
781 | + // карта на странице 'ЖК' | |
782 | + setComplexMap(id, coords, caption) { | |
783 | + | |
784 | + if (document.querySelector('#' + id)) { | |
785 | + | |
786 | + // Дождёмся загрузки API и готовности DOM. | |
787 | + ymaps.ready(init); | |
788 | + | |
789 | + function init() { | |
790 | + const map = new ymaps.Map(id, { | |
791 | + // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования. | |
792 | + center: coords, | |
793 | + zoom: 16, | |
794 | + controls: [] | |
795 | + }); | |
796 | + | |
797 | + // Создаём макет содержимого. | |
798 | + const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( | |
799 | + '<div style="color: #FFFFFF; font-weight: bold;">$[properties.iconContent]</div>' | |
800 | + ); | |
801 | + | |
802 | + // Создание макета содержимого хинта. | |
803 | + // Макет создается через фабрику макетов с помощью текстового шаблона. | |
804 | + const HintLayout = ymaps.templateLayoutFactory.createClass("<div class='my-hint'>" + | |
805 | + "{{ properties.object }}" + "</div>", { | |
806 | + // Определяем метод getShape, который | |
807 | + // будет возвращать размеры макета хинта. | |
808 | + // Это необходимо для того, чтобы хинт автоматически | |
809 | + // сдвигал позицию при выходе за пределы карты. | |
810 | + getShape: function () { | |
811 | + let el = this.getElement(), | |
812 | + result = null; | |
813 | + if (el) { | |
814 | + var firstChild = el.firstChild; | |
815 | + result = new ymaps.shape.Rectangle( | |
816 | + new ymaps.geometry.pixel.Rectangle([ | |
817 | + [0, 0], | |
818 | + [firstChild.offsetWidth, firstChild.offsetHeight] | |
819 | + ]) | |
820 | + ); | |
821 | + } | |
822 | + return result; | |
823 | + } | |
824 | + } | |
825 | + ); | |
826 | + | |
827 | + // метка | |
828 | + const placemark = new ymaps.Placemark(coords, { | |
829 | + // hintContent: caption, | |
830 | + // balloonContent: caption, | |
831 | + iconContent: '1', | |
832 | + // address: caption, | |
833 | + object: caption | |
834 | + }, { | |
835 | + iconLayout: 'default#imageWithContent', | |
836 | + iconImageHref: 'images/mark-complex.svg', | |
837 | + iconImageSize: [52, 67], | |
838 | + iconImageOffset: [-26, -67], | |
839 | + iconContentOffset: [0, 17], | |
840 | + iconContentLayout: MyIconContentLayout, | |
841 | + hintLayout: HintLayout | |
842 | + }); | |
843 | + | |
844 | + map.geoObjects.add(placemark); | |
845 | + | |
846 | + } | |
847 | + | |
848 | + } | |
849 | + | |
850 | + } | |
851 | + | |
852 | + | |
853 | + // фильтры и сортировка на странице 'каталог' | |
854 | + setCatalogSorts() { | |
855 | + | |
856 | + const sortGroups = document.querySelectorAll('.js_sort_group'); | |
857 | + | |
858 | + if (sortGroups.length) { | |
859 | + | |
860 | + sortGroups.forEach(group => { | |
861 | + | |
862 | + const sortGroupInput = group.querySelector('.js_sort_group_input'); | |
863 | + const sortGroupCurrent = group.querySelector('.js_sort_group_current'); | |
864 | + const sortGroupList = group.querySelector('.js_sort_group_list'); | |
865 | + const sortGroupItems = group.querySelectorAll('.js_sort_group_item'); | |
866 | + | |
867 | + const sendRequest = () => { | |
868 | + | |
869 | + const spinner = document.querySelector('.spinner'); // спиннер; | |
870 | + | |
871 | + spinner.classList.add('active'); | |
872 | + document.body.classList.add('overlay'); | |
873 | + /*this.fixBodyPosition(); | |
874 | + | |
875 | + fetch('test.json') | |
876 | + .then(response => response.json()) | |
877 | + .then(data => { | |
878 | + | |
879 | + console.log() | |
880 | + | |
881 | + setTimeout(() => { //имитация ответа сервера | |
882 | + | |
883 | + spinner.classList.remove('active'); | |
884 | + document.body.classList.remove('overlay'); | |
885 | + this.unfixBodyPosition(); | |
886 | + | |
887 | + }, 3000); | |
888 | + | |
889 | + }) | |
890 | + .catch(err => { | |
891 | + console.log(err); | |
892 | + }); | |
893 | + | |
894 | + */ | |
895 | + spinner.classList.remove('active'); | |
896 | + document.body.classList.remove('overlay'); | |
897 | + | |
898 | + | |
899 | + }; | |
900 | + | |
901 | + sortGroupCurrent.addEventListener('click', () => { | |
902 | + | |
903 | + if (group.classList.contains('active')) { | |
904 | + | |
905 | + group.classList.remove('active'); | |
906 | + | |
907 | + } else { | |
908 | + | |
909 | + sortGroups.forEach(group => { | |
910 | + group.classList.remove('active'); | |
911 | + }); | |
912 | + | |
913 | + group.classList.add('active'); | |
914 | + | |
915 | + } | |
916 | + | |
917 | + }); | |
918 | + | |
919 | + sortGroupItems.forEach(item => { | |
920 | + | |
921 | + item.addEventListener('click', () => { | |
922 | + | |
923 | + sortGroupItems.forEach(item => { | |
924 | + item.classList.remove('active'); | |
925 | + }); | |
926 | + | |
927 | + item.classList.add('active'); | |
928 | + sortGroupCurrent.textContent = item.textContent; | |
929 | + sortGroupInput.value = item.dataset.val; | |
930 | + group.classList.remove('active'); | |
931 | + | |
932 | + sendRequest(); | |
933 | + | |
934 | + }); | |
935 | + | |
936 | + }); | |
937 | + | |
938 | + }); | |
939 | + | |
940 | + document.addEventListener('click', (e) => { | |
941 | + | |
942 | + if (!e.target.closest('.js_sort_group_list') && !e.target.closest('.js_sort_group_current')) { | |
943 | + | |
944 | + sortGroups.forEach(group => { | |
945 | + group.classList.remove('active'); | |
946 | + }); | |
947 | + | |
948 | + } | |
949 | + | |
950 | + }); | |
951 | + | |
952 | + } | |
953 | + | |
954 | + } | |
955 | + | |
956 | + | |
957 | + // слайдер на странице жк и на странице предложения | |
958 | + initIntroSlider() { | |
959 | + | |
960 | + let swiper3 = new Swiper('.intro__swiper', { | |
961 | + navigation: { | |
962 | + nextEl: '.swiper-button-next', | |
963 | + prevEl: '.swiper-button-prev', | |
964 | + }, | |
965 | + pagination: { | |
966 | + el: '.swiper-pagination', | |
967 | + clickable: true, | |
968 | + }, | |
969 | + slidesPerView: 1.1, | |
970 | + spaceBetween: 20, | |
971 | + breakpoints: { | |
972 | + 480: { | |
973 | + slidesPerView: 1.5, | |
974 | + }, | |
975 | + 640: { | |
976 | + slidesPerView: 1.75, | |
977 | + }, | |
978 | + 780: { | |
979 | + slidesPerView: 2.15, | |
980 | + }, | |
981 | + 1024: { | |
982 | + slidesPerView: 3.5, | |
983 | + }, | |
984 | + 1200: { | |
985 | + slidesPerView: 1, | |
986 | + } | |
987 | + } | |
988 | + }); | |
989 | + | |
990 | + } | |
991 | + | |
992 | + | |
993 | + // табы на странице предложения | |
994 | + setTabs(tabs, items) { | |
995 | + | |
996 | + const offerSideTabs = document.querySelectorAll(tabs); | |
997 | + const offerSideItems = document.querySelectorAll(items); | |
998 | + | |
999 | + if (offerSideTabs) { | |
1000 | + | |
1001 | + offerSideTabs.forEach(tab => { | |
1002 | + | |
1003 | + tab.addEventListener('click', () => { | |
1004 | + | |
1005 | + offerSideTabs.forEach(tab => { | |
1006 | + tab.classList.remove('active'); | |
1007 | + }); | |
1008 | + | |
1009 | + tab.classList.add('active'); | |
1010 | + | |
1011 | + offerSideItems.forEach(item => { | |
1012 | + | |
1013 | + item.classList.remove('active', 'fade'); | |
1014 | + | |
1015 | + if (tab.dataset.tab == item.dataset.item) { | |
1016 | + item.classList.add('active', 'fade'); | |
1017 | + } | |
1018 | + | |
1019 | + }); | |
1020 | + | |
1021 | + }); | |
1022 | + | |
1023 | + }); | |
1024 | + | |
1025 | + } | |
1026 | + | |
1027 | + } | |
1028 | + | |
1029 | + | |
1030 | + // логика открытия нужного таба при открытии поп-апа с планами объекат и этажа на странице предложения | |
1031 | + sontrolOfferSidePopup() { | |
1032 | + | |
1033 | + const offerSideItems = document.querySelectorAll('.js_offer_side_item'); | |
1034 | + const offerSidePopupTabs = document.querySelectorAll('.js_offer_side_popup_tab'); | |
1035 | + const offerSidePopupItems = document.querySelectorAll('.js_offer_side_popup_item'); | |
1036 | + | |
1037 | + if (offerSideItems) { | |
1038 | + | |
1039 | + offerSideItems.forEach(item => { | |
1040 | + | |
1041 | + const offerSideItemBtn = item.querySelector('.js_offer_side_item_btn'); | |
1042 | + | |
1043 | + offerSideItemBtn.addEventListener('click', (e) => { | |
1044 | + | |
1045 | + e.preventDefault(); | |
1046 | + | |
1047 | + offerSidePopupTabs.forEach(tab => { | |
1048 | + | |
1049 | + tab.classList.remove('active'); | |
1050 | + | |
1051 | + if (item.dataset.item == tab.dataset.tab) { | |
1052 | + tab.classList.add('active'); | |
1053 | + } | |
1054 | + | |
1055 | + }); | |
1056 | + | |
1057 | + offerSidePopupItems.forEach(el => { | |
1058 | + | |
1059 | + el.classList.remove('active', 'fade'); | |
1060 | + | |
1061 | + if (item.dataset.item == el.dataset.item) { | |
1062 | + el.classList.add('active', 'fade'); | |
1063 | + } | |
1064 | + | |
1065 | + }); | |
1066 | + | |
1067 | + }); | |
1068 | + | |
1069 | + }); | |
1070 | + | |
1071 | + } | |
1072 | + | |
1073 | + } | |
1074 | + | |
1075 | + | |
1076 | + // галлерея | |
1077 | + setCustomGallery() { | |
1078 | + | |
1079 | + let swiper4 = new Swiper(".img-viewer__thumbs-swiper", { | |
1080 | + slidesPerView: 3, | |
1081 | + spaceBetween: 8, | |
1082 | + // freeMode: true, | |
1083 | + observer: true, | |
1084 | + observeParents: true, | |
1085 | + observeSlideChildren: true, | |
1086 | + breakpoints: { | |
1087 | + 640: { | |
1088 | + spaceBetween: 10, | |
1089 | + }, | |
1090 | + }, | |
1091 | + }); | |
1092 | + | |
1093 | + let swiper5 = new Swiper(".img-viewer__slider .swiper", { | |
1094 | + navigation: { | |
1095 | + nextEl: ".img-viewer__slider .swiper-button-next", | |
1096 | + prevEl: ".img-viewer__slider .swiper-button-prev", | |
1097 | + }, | |
1098 | + slidesPerView: 1, | |
1099 | + spaceBetween: 20, | |
1100 | + thumbs: { | |
1101 | + swiper: swiper4 | |
1102 | + }, | |
1103 | + observer: true, | |
1104 | + observeParents: true, | |
1105 | + observeSlideChildren: true, | |
1106 | + }); | |
1107 | + | |
1108 | + if (document.querySelector('.js_intro_item_btn')) { | |
1109 | + | |
1110 | + const imgViewer = document.querySelector('.js_img_viewer'); | |
1111 | + const imgViewerCloses = imgViewer.querySelectorAll('.js_img_viewer_close'); | |
1112 | + const imgViewerCaption = imgViewer.querySelector('.js_img_viewer_caption'); | |
1113 | + | |
1114 | + const imgViewerSliderSwiper = imgViewer.querySelector('.js_img_viewer_slider_swiper'); | |
1115 | + const imgViewerSliderSwiperWrap = imgViewerSliderSwiper.querySelector('.js_img_viewer_slider_swiper .swiper-wrapper'); | |
1116 | + | |
1117 | + const imgViewerThumbsSwiper = imgViewer.querySelector('.js_img_viewer_thumbs_swiper'); | |
1118 | + const imgViewerThumbsSwiperWrap = imgViewerThumbsSwiper.querySelector('.js_img_viewer_thumbs_swiper .swiper-wrapper'); | |
1119 | + | |
1120 | + const introItemBtns = document.querySelectorAll('.js_intro_item_btn'); | |
1121 | + | |
1122 | + introItemBtns.forEach((btn, i) => { | |
1123 | + | |
1124 | + btn.addEventListener('click', (e) => { | |
1125 | + | |
1126 | + e.preventDefault(); | |
1127 | + | |
1128 | + imgViewer.classList.add('active'); | |
1129 | + this.fixBodyPosition(); | |
1130 | + | |
1131 | + imgViewerSliderSwiperWrap.innerHTML = ''; | |
1132 | + imgViewerThumbsSwiperWrap.innerHTML = ''; | |
1133 | + imgViewerCaption.textContent = ''; | |
1134 | + | |
1135 | + | |
1136 | + introItemBtns.forEach(btn => { | |
1137 | + | |
1138 | + imgViewerSliderSwiperWrap.insertAdjacentHTML('beforeend', ` | |
1139 | + <div class="swiper-slide"> | |
1140 | + <img src="${btn.getAttribute('href')}" alt=""> | |
1141 | + </div>` | |
1142 | + ); | |
1143 | + | |
1144 | + imgViewerThumbsSwiperWrap.insertAdjacentHTML('beforeend', ` | |
1145 | + <div class="swiper-slide"> | |
1146 | + <img src="${btn.getAttribute('href')}" alt=""> | |
1147 | + </div>` | |
1148 | + ); | |
1149 | + | |
1150 | + }); | |
1151 | + | |
1152 | + swiper4.update(); | |
1153 | + swiper5.update(); | |
1154 | + swiper5.slideTo(i); | |
1155 | + imgViewerCaption.textContent = btn.dataset.caption; | |
1156 | + | |
1157 | + }); | |
1158 | + | |
1159 | + }); | |
1160 | + | |
1161 | + swiper5.on('slideChange', function () { | |
1162 | + imgViewerCaption.textContent = introItemBtns[swiper5.realIndex].dataset.caption; | |
1163 | + }); | |
1164 | + | |
1165 | + imgViewerCloses.forEach(close => { | |
1166 | + | |
1167 | + close.addEventListener('click', () => { | |
1168 | + | |
1169 | + imgViewer.classList.remove('active'); | |
1170 | + this.unfixBodyPosition(); | |
1171 | + | |
1172 | + }); | |
1173 | + | |
1174 | + }); | |
1175 | + | |
1176 | + } | |
1177 | + | |
1178 | + } | |
1179 | + | |
1180 | + | |
1181 | + // куки | |
1182 | + setCookies() { | |
1183 | + | |
1184 | + const cookies = document.querySelector('.js_cookies'); | |
1185 | + const cookiesBtn = document.querySelector('.js_cookies_confirm'); | |
1186 | + const cookiesTrigger = document.querySelector('.js_btn_cookies'); | |
1187 | + | |
1188 | + if (cookiesTrigger) { | |
1189 | + | |
1190 | + cookiesTrigger.addEventListener('click', () => { | |
1191 | + cookies.classList.add('active'); | |
1192 | + }); | |
1193 | + | |
1194 | + }; | |
1195 | + | |
1196 | + if (cookies) { | |
1197 | + | |
1198 | + cookiesBtn.addEventListener('click', () => { | |
1199 | + cookies.classList.remove('active'); | |
1200 | + }); | |
1201 | + | |
1202 | + }; | |
1203 | + | |
1204 | + } | |
1205 | + | |
1206 | + | |
1207 | + // карта на странице карт; | |
1208 | + /* | |
1209 | + //setGeneralMap() { | |
1210 | + | |
1211 | + if (document.querySelector('#general-map')) { | |
1212 | + | |
1213 | + ymaps.ready(init); // Дождёмся загрузки API и готовности DOM; | |
1214 | + | |
1215 | + function init() { | |
1216 | + | |
1217 | + const myMap = new ymaps.Map('general-map', { // Создание экземпляра карты и его привязка к контейнеру с заданным id; | |
1218 | + center: [55.752933963675126, 37.52233749962665], // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования; | |
1219 | + zoom: 10, | |
1220 | + controls: [] // Скрываем элементы управления на карте; | |
1221 | + }); | |
1222 | + | |
1223 | + // Создаём макет содержимого. | |
1224 | + const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( | |
1225 | + '<div style="color: #FFFFFF; font-weight: bold;">$[properties.iconContent]</div>' | |
1226 | + ); | |
1227 | + | |
1228 | + let collection = new ymaps.GeoObjectCollection(null, { // Создаём коллекцию, в которую будемпомещать метки (что-то типа массива); | |
1229 | + // preset: 'islands#yellowIcon' | |
1230 | + }); | |
1231 | + | |
1232 | + let collectionCoords = [ // Создаём массив с координатами (координаты должны располагаться в том же порядке, что и адреса в списке на сайте); | |
1233 | + [55.867783219108354, 37.392867499999916], | |
1234 | + [55.728043075486504, 37.73937949999994], | |
1235 | + [55.72624100423305, 37.476078499999964], | |
1236 | + [55.80751105044832, 37.449622999999974], | |
1237 | + [55.601783098948836, 37.36700499999998], | |
1238 | + [55.86086502152225, 37.540348999999964], | |
1239 | + [55.784961528728715, 37.56188599999996], | |
1240 | + [55.63910010399773, 37.319407999999996], | |
1241 | + [55.55819256767507, 37.55711549999994], | |
1242 | + [55.79829252928473, 37.52063549999999], | |
1243 | + ]; | |
1244 | + | |
1245 | + for (let i = 0, l = collectionCoords.length; i < l; i++) { // C помощью цикла добавляем все метки в коллекцию; | |
1246 | + collection.add(new ymaps.Placemark(collectionCoords[i])); | |
1247 | + collection.get(i).properties.set('iconContent', `${i + 1}`); // Добавляем каждой метке порядковый номер, записываем его в свойство 'iconContent'; | |
1248 | + } | |
1249 | + | |
1250 | + myMap.geoObjects.add(collection); // Добавляем коллекцию с метками на карту; | |
1251 | + | |
1252 | + collection.options.set('iconLayout', 'default#imageWithContent'); // Необходимо указать данный тип макета; | |
1253 | + collection.options.set('iconImageHref', 'images/mark-complex.svg'); // Своё изображение иконки метки; | |
1254 | + collection.options.set('iconImageSize', [52, 67]); // Размеры метки; | |
1255 | + collection.options.set('iconImageOffset', [-26, -67]); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); | |
1256 | + collection.options.set('iconContentOffset', [0, 17]); | |
1257 | + collection.options.set('iconContentLayout', MyIconContentLayout); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); | |
1258 | + | |
1259 | + const pageMapBar = document.querySelector('.js_page_map_bar'); | |
1260 | + const pageMapBarBtn = pageMapBar.querySelector('.js_page_map_bar_btn'); | |
1261 | + const pageMapBarList = pageMapBar.querySelector('.js_page_map_bar_list'); | |
1262 | + const pageMapBarCards = pageMapBar.querySelectorAll('.card-news'); | |
1263 | + | |
1264 | + const showCard = (i) => { | |
1265 | + | |
1266 | + pageMapBarCards.forEach((card, k) => { | |
1267 | + | |
1268 | + card.classList.remove('active'); | |
1269 | + | |
1270 | + if (i == k) { | |
1271 | + card.classList.add('active'); | |
1272 | + } | |
1273 | + | |
1274 | + }); | |
1275 | + | |
1276 | + }; | |
1277 | + | |
1278 | + const hidecard = () => { | |
1279 | + | |
1280 | + pageMapBarCards.forEach(card => { | |
1281 | + card.classList.remove('active'); | |
1282 | + }); | |
1283 | + | |
1284 | + } | |
1285 | + | |
1286 | + let pageMapBarItems; | |
1287 | + | |
1288 | + pageMapBarBtn.addEventListener('click', () => { | |
1289 | + pageMapBar.classList.toggle('active'); | |
1290 | + }); | |
1291 | + | |
1292 | + pageMapBarList.addEventListener('click', (e) => { | |
1293 | + | |
1294 | + if (e.target.closest('.page-map-bar__item')) { | |
1295 | + | |
1296 | + pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); | |
1297 | + | |
1298 | + pageMapBarItems.forEach((item, i) => { | |
1299 | + | |
1300 | + if (e.target == item && e.target.classList.contains('active')) { | |
1301 | + | |
1302 | + item.classList.remove('active'); | |
1303 | + | |
1304 | + hidecard(); | |
1305 | + | |
1306 | + } else if (e.target == item) { | |
1307 | + | |
1308 | + pageMapBarItems.forEach(item => { | |
1309 | + item.classList.remove('active'); | |
1310 | + }); | |
1311 | + | |
1312 | + item.classList.add('active'); | |
1313 | + | |
1314 | + let offsetCoords = collection.get(i).geometry.getCoordinates(); | |
1315 | + | |
1316 | + offsetCoords = [ | |
1317 | + offsetCoords[0] - 0.0025, | |
1318 | + offsetCoords[1] | |
1319 | + ]; | |
1320 | + | |
1321 | + myMap.setZoom(16); | |
1322 | + // myMap.setCenter(collection.get(i).geometry.getCoordinates()); | |
1323 | + myMap.setCenter(offsetCoords); | |
1324 | + | |
1325 | + showCard(i); | |
1326 | + | |
1327 | + } | |
1328 | + | |
1329 | + }); | |
1330 | + } | |
1331 | + | |
1332 | + }); | |
1333 | + | |
1334 | + collection.events.add('click', function (e) { | |
1335 | + | |
1336 | + for (let i = 0, l = collection.getLength(); i < l; i++) { | |
1337 | + | |
1338 | + if (e.get('target') == collection.get(i)) { | |
1339 | + | |
1340 | + pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); | |
1341 | + | |
1342 | + pageMapBarItems.forEach((item) => { | |
1343 | + pageMapBar.classList.add('active'); | |
1344 | + item.classList.remove('active'); | |
1345 | + }); | |
1346 | + | |
1347 | + pageMapBarItems[i].classList.add('active'); | |
1348 | + | |
1349 | + showCard(i); | |
1350 | + | |
1351 | + } | |
1352 | + | |
1353 | + } | |
1354 | + | |
1355 | + }); | |
1356 | + | |
1357 | + } | |
1358 | + | |
1359 | + } | |
1360 | + | |
1361 | + };*/ | |
1362 | + | |
1363 | + | |
1364 | + // аккордеон в футере | |
1365 | + setFooterSpoilers() { | |
1366 | + | |
1367 | + const items = document.querySelectorAll('.js_footer_col'); | |
1368 | + | |
1369 | + items.forEach(item => { | |
1370 | + | |
1371 | + const itemTitle = item.querySelector('.js_footer_caption'); | |
1372 | + const itemContent = item.querySelector('.js_footer_block'); | |
1373 | + | |
1374 | + const blockToggle = (block, duration) => { | |
1375 | + | |
1376 | + if (window.getComputedStyle(block).display == "none" && !block.classList.contains('smooth')) { | |
1377 | + | |
1378 | + block.style.display = "block"; | |
1379 | + | |
1380 | + const blockHeight = block.offsetHeight; | |
1381 | + | |
1382 | + block.style.height = 0; | |
1383 | + block.style.overflow = "hidden"; | |
1384 | + block.style.transition = `height ${duration}ms ease`; | |
1385 | + block.classList.add('smooth'); | |
1386 | + block.offsetHeight; | |
1387 | + block.style.height = `${blockHeight}px`; | |
1388 | + | |
1389 | + setTimeout(() => { | |
1390 | + | |
1391 | + block.classList.remove('smooth'); | |
1392 | + block.style.height = ''; | |
1393 | + block.style.transition = ''; | |
1394 | + block.style.overflow = ''; | |
1395 | + | |
1396 | + }, duration); | |
1397 | + | |
1398 | + } else if (!block.classList.contains('smooth')) { | |
1399 | + | |
1400 | + block.style.height = `${block.offsetHeight}px`; | |
1401 | + block.offsetHeight; | |
1402 | + block.style.height = 0; | |
1403 | + block.style.overflow = "hidden"; | |
1404 | + block.style.transition = `height ${duration}ms ease`; | |
1405 | + block.classList.add('smooth'); | |
1406 | + | |
1407 | + setTimeout(() => { | |
1408 | + | |
1409 | + block.classList.remove('smooth'); | |
1410 | + block.style.display = "none"; | |
1411 | + block.style.height = ''; | |
1412 | + block.style.transition = ''; | |
1413 | + block.style.overflow = ''; | |
1414 | + | |
1415 | + }, duration); | |
1416 | + | |
1417 | + } | |
1418 | + | |
1419 | + }; | |
1420 | + | |
1421 | + itemTitle.addEventListener('click', (e) => { | |
1422 | + itemTitle.classList.toggle('active'); | |
1423 | + blockToggle(itemContent, 300); | |
1424 | + }); | |
1425 | + | |
1426 | + }); | |
1427 | + | |
1428 | + } | |
1429 | + | |
1430 | + | |
1431 | + // слайдер с партнёрами; | |
1432 | + initPartnerslSlider() { | |
1433 | + | |
1434 | + const slider = document.querySelector('.partners__swiper'); | |
1435 | + | |
1436 | + if (slider) { | |
1437 | + | |
1438 | + let swiper6; | |
1439 | + | |
1440 | + const initSlider = () => { | |
1441 | + | |
1442 | + swiper6 = new Swiper(slider, { | |
1443 | + // scrollbar: { | |
1444 | + // el: '.swiper-scrollbar', | |
1445 | + // draggable: true, | |
1446 | + // }, | |
1447 | + slidesPerView: 0.275, | |
1448 | + loop: true, | |
1449 | + spaceBetween: 20, | |
1450 | + freeMode: true, | |
1451 | + allowTouchMove: true, | |
1452 | + breakpoints: { | |
1453 | + 480: { | |
1454 | + slidesPerView: 0.4, | |
1455 | + }, | |
1456 | + 640: { | |
1457 | + slidesPerView: 0.65, | |
1458 | + }, | |
1459 | + 780: { | |
1460 | + slidesPerView: 0.65, | |
1461 | + }, | |
1462 | + 1024: { | |
1463 | + slidesPerView: 0.8, | |
1464 | + }, | |
1465 | + 1200: { | |
1466 | + slidesPerView: 1, | |
1467 | + loop: false, | |
1468 | + allowTouchMove: false, | |
1469 | + } | |
1470 | + } | |
1471 | + }); | |
1472 | + | |
1473 | + }; | |
1474 | + | |
1475 | + initSlider(); | |
1476 | + | |
1477 | + const updateSlider = () => { | |
1478 | + swiper6.destroy(); | |
1479 | + initSlider(); | |
1480 | + } | |
1481 | + | |
1482 | + window.addEventListener('resize', () => { | |
1483 | + | |
1484 | + if (window.innerWidth <= 1200 && slider.dataset.mobile == 'false') { | |
1485 | + slider.dataset.mobile = 'true'; | |
1486 | + updateSlider(); | |
1487 | + } | |
1488 | + | |
1489 | + if (window.innerWidth > 1200 && slider.dataset.mobile == 'true') { | |
1490 | + slider.dataset.mobile = 'false'; | |
1491 | + updateSlider(); | |
1492 | + } | |
1493 | + | |
1494 | + }); | |
1495 | + | |
1496 | + } | |
1497 | + | |
1498 | + } | |
1499 | + | |
1500 | +} | |
1501 | + | |
1502 | + | |
1503 | +document.addEventListener('DOMContentLoaded', () => { | |
1504 | + | |
1505 | + const app = new App(); | |
1506 | + app.init(); | |
1507 | + | |
1508 | +}); |
public/pug/templates/scripts.pug
resources/views/admin/houses/form.blade.php
... | ... | @@ -474,9 +474,13 @@ |
474 | 474 | <input type="text" class="form-control_ txt" name="scheme_deal" placeholder="Схема сделки" |
475 | 475 | required maxlength="100" style="width: 80%" value="{{ old('scheme_deal') ?? $house->scheme_deal ?? '' }}"><br><br> |
476 | 476 | |
477 | -<label for="map_coord">Координаты дома: </label><br> | |
478 | -<input type="text" class="form-control_ txt" name="map_coord" placeholder="Координаты дома" | |
479 | - required maxlength="100" value="{{ old('map_coord') ?? $house->map_coord ?? '' }}"><br><br> | |
477 | +<label for="coord_x">Координаты дома X: </label><br> | |
478 | +<input type="text" class="form-control_ txt" name="coord_x" placeholder="Координаты дома X" | |
479 | + required maxlength="100" value="{{ old('coord_x') ?? $house->coord_x ?? '0' }}"><br><br> | |
480 | + | |
481 | +<label for="coord_y">Координаты дома Y: </label><br> | |
482 | +<input type="text" class="form-control_ txt" name="coord_y" placeholder="Координаты дома Y" | |
483 | + required maxlength="100" value="{{ old('coord_y') ?? $house->coord_y ?? '0' }}"><br><br> | |
480 | 484 | |
481 | 485 | <label for="sos_obj">Состояние объекта: </label><br> |
482 | 486 | @error('sos_obj') |
resources/views/index.blade.php
resources/views/layout/admin.blade.php
... | ... | @@ -457,7 +457,7 @@ |
457 | 457 | </div> |
458 | 458 | <script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script> |
459 | 459 | <script src="{{ asset('js/swiper-bundle.min.js') }}"></script> |
460 | -<script src="{{ asset('js/main.js') }}"></script> | |
460 | +<script src="{{ asset('js/main_new.js') }}"></script> | |
461 | 461 | <script type="text/javascript" src="{{ asset('js/jquery.min.js') }}"></script> |
462 | 462 | <script type="text/javascript" src="{{ asset('js/jquery.cookie.js') }}"></script> |
463 | 463 | @yield('custom_js') |
resources/views/layout/site.blade.php
... | ... | @@ -413,7 +413,7 @@ |
413 | 413 | </div> |
414 | 414 | <script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script> |
415 | 415 | <script src="{{ asset('js/swiper-bundle.min.js') }}"></script> |
416 | -<script src="{{ asset('js/main.js') }}"></script> | |
416 | +<script src="{{ asset('js/main_new.js') }}"></script> | |
417 | 417 | <script type="text/javascript" src="{{ asset('js/jquery.min.js') }}"></script> |
418 | 418 | <script type="text/javascript" src="{{ asset('js/jquery.cookie.js') }}"></script> |
419 | 419 | @yield('custom_js') |
resources/views/mapsobj.blade.php
... | ... | @@ -6,6 +6,168 @@ |
6 | 6 | |
7 | 7 | @section('custom_js') |
8 | 8 | @include('js.filter_value') |
9 | + <script> | |
10 | + function setGeneralMap() { | |
11 | + | |
12 | + if (document.querySelector('#general-map')) { | |
13 | + | |
14 | + ymaps.ready(init); // Дождёмся загрузки API и готовности DOM; | |
15 | + | |
16 | + function init() { | |
17 | + | |
18 | + const myMap = new ymaps.Map('general-map', { // Создание экземпляра карты и его привязка к контейнеру с заданным id; | |
19 | + center: [55.752933963675126, 37.52233749962665], // При инициализации карты обязательно нужно указать её центр и коэффициент масштабирования; | |
20 | + zoom: 10, | |
21 | + controls: [] // Скрываем элементы управления на карте; | |
22 | + }); | |
23 | + | |
24 | + // Создаём макет содержимого. | |
25 | + const MyIconContentLayout = ymaps.templateLayoutFactory.createClass( | |
26 | + '<div style="color: #FFFFFF; font-weight: bold;">$[properties.iconContent]</div>' | |
27 | + ); | |
28 | + | |
29 | + let collection = new ymaps.GeoObjectCollection(null, { // Создаём коллекцию, в которую будемпомещать метки (что-то типа массива); | |
30 | + // preset: 'islands#yellowIcon' | |
31 | + }); | |
32 | + | |
33 | + let collectionCoords = [ // Создаём массив с координатами (координаты должны располагаться в том же порядке, что и адреса в списке на сайте); | |
34 | + @if ($areas->count()) | |
35 | + @foreach ($areas as $area) | |
36 | + [{{ $area->coord_x }}, {{$area->coord_y}}], | |
37 | + @endforeach | |
38 | + @endif | |
39 | + // [55.867783219108354, 37.392867499999916], | |
40 | + // [55.728043075486504, 37.73937949999994], | |
41 | + // [55.72624100423305, 37.476078499999964], | |
42 | + // [55.80751105044832, 37.449622999999974], | |
43 | + // [55.601783098948836, 37.36700499999998], | |
44 | + // [55.86086502152225, 37.540348999999964], | |
45 | + // [55.784961528728715, 37.56188599999996], | |
46 | + // [55.63910010399773, 37.319407999999996], | |
47 | + // [55.55819256767507, 37.55711549999994], | |
48 | + // [55.79829252928473, 37.52063549999999], | |
49 | + ]; | |
50 | + | |
51 | + for (let i = 0, l = collectionCoords.length; i < l; i++) { // C помощью цикла добавляем все метки в коллекцию; | |
52 | + collection.add(new ymaps.Placemark(collectionCoords[i])); | |
53 | + collection.get(i).properties.set('iconContent', `${i + 1}`); // Добавляем каждой метке порядковый номер, записываем его в свойство 'iconContent'; | |
54 | + } | |
55 | + | |
56 | + myMap.geoObjects.add(collection); // Добавляем коллекцию с метками на карту; | |
57 | + | |
58 | + collection.options.set('iconLayout', 'default#imageWithContent'); // Необходимо указать данный тип макета; | |
59 | + collection.options.set('iconImageHref', 'images/mark-complex.svg'); // Своё изображение иконки метки; | |
60 | + collection.options.set('iconImageSize', [52, 67]); // Размеры метки; | |
61 | + collection.options.set('iconImageOffset', [-26, -67]); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); | |
62 | + collection.options.set('iconContentOffset', [0, 17]); | |
63 | + collection.options.set('iconContentLayout', MyIconContentLayout); // Смещение левого верхнего угла иконки относительно её "ножки" (точки привязки); | |
64 | + | |
65 | + const pageMapBar = document.querySelector('.js_page_map_bar'); | |
66 | + const pageMapBarBtn = pageMapBar.querySelector('.js_page_map_bar_btn'); | |
67 | + const pageMapBarList = pageMapBar.querySelector('.js_page_map_bar_list'); | |
68 | + const pageMapBarCards = pageMapBar.querySelectorAll('.card-news'); | |
69 | + | |
70 | + const showCard = (i) => { | |
71 | + | |
72 | + pageMapBarCards.forEach((card, k) => { | |
73 | + | |
74 | + card.classList.remove('active'); | |
75 | + | |
76 | + if (i == k) { | |
77 | + card.classList.add('active'); | |
78 | + } | |
79 | + | |
80 | + }); | |
81 | + | |
82 | + }; | |
83 | + | |
84 | + const hidecard = () => { | |
85 | + | |
86 | + pageMapBarCards.forEach(card => { | |
87 | + card.classList.remove('active'); | |
88 | + }); | |
89 | + | |
90 | + } | |
91 | + | |
92 | + let pageMapBarItems; | |
93 | + | |
94 | + pageMapBarBtn.addEventListener('click', () => { | |
95 | + pageMapBar.classList.toggle('active'); | |
96 | + }); | |
97 | + | |
98 | + pageMapBarList.addEventListener('click', (e) => { | |
99 | + | |
100 | + if (e.target.closest('.page-map-bar__item')) { | |
101 | + | |
102 | + pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); | |
103 | + | |
104 | + pageMapBarItems.forEach((item, i) => { | |
105 | + | |
106 | + if (e.target == item && e.target.classList.contains('active')) { | |
107 | + | |
108 | + item.classList.remove('active'); | |
109 | + | |
110 | + hidecard(); | |
111 | + | |
112 | + } else if (e.target == item) { | |
113 | + | |
114 | + pageMapBarItems.forEach(item => { | |
115 | + item.classList.remove('active'); | |
116 | + }); | |
117 | + | |
118 | + item.classList.add('active'); | |
119 | + | |
120 | + let offsetCoords = collection.get(i).geometry.getCoordinates(); | |
121 | + | |
122 | + offsetCoords = [ | |
123 | + offsetCoords[0] - 0.0025, | |
124 | + offsetCoords[1] | |
125 | + ]; | |
126 | + | |
127 | + myMap.setZoom(16); | |
128 | + // myMap.setCenter(collection.get(i).geometry.getCoordinates()); | |
129 | + myMap.setCenter(offsetCoords); | |
130 | + | |
131 | + showCard(i); | |
132 | + | |
133 | + } | |
134 | + | |
135 | + }); | |
136 | + } | |
137 | + | |
138 | + }); | |
139 | + | |
140 | + collection.events.add('click', function (e) { | |
141 | + | |
142 | + for (let i = 0, l = collection.getLength(); i < l; i++) { | |
143 | + | |
144 | + if (e.get('target') == collection.get(i)) { | |
145 | + | |
146 | + pageMapBarItems = pageMapBarList.querySelectorAll('.page-map-bar__item'); | |
147 | + | |
148 | + pageMapBarItems.forEach((item) => { | |
149 | + pageMapBar.classList.add('active'); | |
150 | + item.classList.remove('active'); | |
151 | + }); | |
152 | + | |
153 | + pageMapBarItems[i].classList.add('active'); | |
154 | + | |
155 | + showCard(i); | |
156 | + | |
157 | + } | |
158 | + | |
159 | + } | |
160 | + | |
161 | + }); | |
162 | + | |
163 | + } | |
164 | + | |
165 | + } | |
166 | + | |
167 | + } | |
168 | + | |
169 | + setGeneralMap(); | |
170 | + </script> | |
9 | 171 | @endsection |
10 | 172 | |
11 | 173 | @section('content') |
... | ... | @@ -24,7 +186,12 @@ |
24 | 186 | </button> |
25 | 187 | </div> |
26 | 188 | <ul class="page-map-bar__list js_page_map_bar_list"> |
27 | - <li class="page-map-bar__item">ЖК Большое Путилково</li> | |
189 | + @if ($areas->count()) | |
190 | + @foreach ($areas as $area) | |
191 | + <li class="page-map-bar__item">{{ $area->name_area }}</li> | |
192 | + @endforeach | |
193 | + @endif | |
194 | + <!--<li class="page-map-bar__item">ЖК Большое Путилково</li> | |
28 | 195 | <li class="page-map-bar__item">ЖК Среда</li> |
29 | 196 | <li class="page-map-bar__item">ЖК Квартал Триумфальный</li> |
30 | 197 | <li class="page-map-bar__item">ЖК Алые Паруса</li> |
... | ... | @@ -33,9 +200,26 @@ |
33 | 200 | <li class="page-map-bar__item">ЖК Царская Площадь</li> |
34 | 201 | <li class="page-map-bar__item">ЖК Переделкино Ближнее</li> |
35 | 202 | <li class="page-map-bar__item">ЖК Этолон Cити</li> |
36 | - <li class="page-map-bar__item">ЖК Триумф Палас</li> | |
203 | + <li class="page-map-bar__item">ЖК Триумф Палас</li>--> | |
37 | 204 | </ul> |
38 | - <div class="card-news"> | |
205 | + @if ($areas->count()) | |
206 | + @foreach ($areas as $area) | |
207 | + <div class="card-news"> | |
208 | + <div class="card-news__top"><img src="{{ asset(Storage::url($area->foto_main)) }}" alt="Превью по {{$area->name_area}}" loading="lazy"> | |
209 | + <div class="card-news__date"><span>{{ $area->name_area }}</span><span></span></div> | |
210 | + </div> | |
211 | + <div class="card-news__cnt"> | |
212 | + <p class="card-news__descr">{{ $area->description }}</p> | |
213 | + <a class="card-news__link" href="{{ route('complex', ['area' => $area->id]) }}">Подробнее | |
214 | + <svg width="17" height="12"> | |
215 | + <use xlink:href="{{ asset('images/sprite.svg#card-news-link-arrow') }}"></use> | |
216 | + </svg> | |
217 | + </a> | |
218 | + </div> | |
219 | + </div> | |
220 | + @endforeach | |
221 | + @endif | |
222 | + <!--<div class="card-news"> | |
39 | 223 | <div class="card-news__top"><img src="images/card/card-img-5.jpg" alt="Превью к новости" loading="lazy"> |
40 | 224 | <div class="card-news__date"><span>ЖК Большое Путилково</span><span></span></div> |
41 | 225 | </div> |
... | ... | @@ -144,7 +328,7 @@ |
144 | 328 | <use xlink:href="images/sprite.svg#card-news-link-arrow"></use> |
145 | 329 | </svg></a> |
146 | 330 | </div> |
147 | - </div> | |
331 | + </div>--> | |
148 | 332 | </div> |
149 | 333 | </div> |
150 | 334 | </div> |