github.com/wanliu/go-oauth2-server@v0.0.0-20180817021415-f928fa1580df/public/js/main.js (about) 1 { 2 class Details { 3 constructor() { 4 this.DOM = {}; 5 6 const detailsTmpl = ` 7 <div class="details__bg details__bg--down"> 8 <button class="details__close"><i class="fas fa-2x fa-times icon--cross tm-fa-close"></i></button> 9 <div class="details__description"></div> 10 </div> 11 `; 12 13 this.DOM.details = document.createElement('div'); 14 this.DOM.details.className = 'details'; 15 this.DOM.details.innerHTML = detailsTmpl; 16 // DOM.content.appendChild(this.DOM.details); 17 document.getElementById('tm-wrap').appendChild(this.DOM.details); 18 this.init(); 19 } 20 init() { 21 this.DOM.bgDown = this.DOM.details.querySelector('.details__bg--down'); 22 this.DOM.description = this.DOM.details.querySelector('.details__description'); 23 this.DOM.close = this.DOM.details.querySelector('.details__close'); 24 25 this.initEvents(); 26 } 27 initEvents() { 28 // close page when outside of page is clicked. 29 document.body.addEventListener('click', () => this.close()); 30 // prevent close page when inside of page is clicked. 31 this.DOM.bgDown.addEventListener('click', function(event) { 32 event.stopPropagation(); 33 }); 34 // close page when cross button is clicked. 35 this.DOM.close.addEventListener('click', () => this.close()); 36 } 37 fill(info) { 38 // fill current page info 39 this.DOM.description.innerHTML = info.description; 40 } 41 getProductDetailsRect(){ 42 var p = 0; 43 var d = 0; 44 45 try { 46 p = this.DOM.productBg.getBoundingClientRect(); 47 d = this.DOM.bgDown.getBoundingClientRect(); 48 } 49 catch(e){} 50 51 return { 52 productBgRect: p, 53 detailsBgRect: d 54 }; 55 } 56 open(data) { 57 if(this.isAnimating) return false; 58 this.isAnimating = true; 59 60 this.DOM.details.style.display = 'block'; 61 62 this.DOM.details.classList.add('details--open'); 63 64 this.DOM.productBg = data.productBg; 65 66 this.DOM.productBg.style.opacity = 0; 67 68 const rect = this.getProductDetailsRect(); 69 70 this.DOM.bgDown.style.transform = `translateX(${rect.productBgRect.left-rect.detailsBgRect.left}px) translateY(${rect.productBgRect.top-rect.detailsBgRect.top}px) scaleX(${rect.productBgRect.width/rect.detailsBgRect.width}) scaleY(${rect.productBgRect.height/rect.detailsBgRect.height})`; 71 this.DOM.bgDown.style.opacity = 1; 72 73 // animate background 74 anime({ 75 targets: [this.DOM.bgDown], 76 duration: (target, index) => index ? 800 : 250, 77 easing: (target, index) => index ? 'easeOutElastic' : 'easeOutSine', 78 elasticity: 250, 79 translateX: 0, 80 translateY: 0, 81 scaleX: 1, 82 scaleY: 1, 83 complete: () => this.isAnimating = false 84 }); 85 86 // animate content 87 anime({ 88 targets: [this.DOM.description], 89 duration: 1000, 90 easing: 'easeOutExpo', 91 translateY: ['100%',0], 92 opacity: 1 93 }); 94 95 // animate close button 96 anime({ 97 targets: this.DOM.close, 98 duration: 250, 99 easing: 'easeOutSine', 100 translateY: ['100%',0], 101 opacity: 1 102 }); 103 104 this.setCarousel(); 105 106 window.addEventListener("resize", this.setCarousel); 107 } 108 close() { 109 if(this.isAnimating) return false; 110 this.isAnimating = true; 111 112 this.DOM.details.classList.remove('details--open'); 113 114 anime({ 115 targets: this.DOM.close, 116 duration: 250, 117 easing: 'easeOutSine', 118 translateY: '100%', 119 opacity: 0 120 }); 121 122 anime({ 123 targets: [this.DOM.description], 124 duration: 20, 125 easing: 'linear', 126 opacity: 0 127 }); 128 129 const rect = this.getProductDetailsRect(); 130 anime({ 131 targets: [this.DOM.bgDown], 132 duration: 250, 133 easing: 'easeOutSine', 134 translateX: (target, index) => { 135 return index ? rect.productImgRect.left-rect.detailsImgRect.left : rect.productBgRect.left-rect.detailsBgRect.left; 136 }, 137 translateY: (target, index) => { 138 return index ? rect.productImgRect.top-rect.detailsImgRect.top : rect.productBgRect.top-rect.detailsBgRect.top; 139 }, 140 scaleX: (target, index) => { 141 return index ? rect.productImgRect.width/rect.detailsImgRect.width : rect.productBgRect.width/rect.detailsBgRect.width; 142 }, 143 scaleY: (target, index) => { 144 return index ? rect.productImgRect.height/rect.detailsImgRect.height : rect.productBgRect.height/rect.detailsBgRect.height; 145 }, 146 complete: () => { 147 this.DOM.bgDown.style.opacity = 0; 148 this.DOM.bgDown.style.transform = 'none'; 149 this.DOM.productBg.style.opacity = 1; 150 this.DOM.details.style.display = 'none'; 151 this.isAnimating = false; 152 } 153 }); 154 } 155 // Slick Carousel 156 setCarousel() { 157 158 var slider = $('.details .tm-img-slider'); 159 160 if(slider.length) { // check if slider exist 161 162 if (slider.hasClass('slick-initialized')) { 163 slider.slick('destroy'); 164 } 165 166 if($(window).width() > 767){ 167 // Slick carousel 168 slider.slick({ 169 dots: true, 170 infinite: true, 171 slidesToShow: 4, 172 slidesToScroll: 3 173 }); 174 } 175 else { 176 slider.slick({ 177 dots: true, 178 infinite: true, 179 slidesToShow: 2, 180 slidesToScroll: 1 181 }); 182 } 183 } 184 } 185 }; // class Details 186 187 class Item { 188 constructor(el) { 189 this.DOM = {}; 190 this.DOM.el = el; 191 this.DOM.product = this.DOM.el.querySelector('.product'); 192 this.DOM.productBg = this.DOM.product.querySelector('.product__bg'); 193 194 this.info = { 195 description: this.DOM.product.querySelector('.product__description').innerHTML 196 }; 197 198 this.initEvents(); 199 } 200 initEvents() { 201 this.DOM.product.addEventListener('click', () => this.open()); 202 } 203 open() { 204 DOM.details.fill(this.info); 205 DOM.details.open({ 206 productBg: this.DOM.productBg 207 }); 208 } 209 }; // class Item 210 211 const DOM = {}; 212 DOM.grid = document.querySelector('.grid'); 213 DOM.content = DOM.grid.parentNode; 214 DOM.gridItems = Array.from(DOM.grid.querySelectorAll('.grid__item')); 215 let items = []; 216 DOM.gridItems.forEach(item => items.push(new Item(item))); 217 218 DOM.details = new Details(); 219 }; 220 221