1import Vue from './vue.esm.browser.js'; 2 3var newDiv = document.createElement("div"); 4newDiv.id = "popups"; 5newDiv.innerHTML = "<popup-component />"; 6 7document.body.appendChild(newDiv); 8 9loadVueInstance(); 10 11function loadVueInstance() { 12 Vue.component('popup-component', { 13 template: ` 14 <div v-if="!isClosed" :class="{'popup-component__overlay': getPopupBlackout}" @click="isClosed = true"> 15 <div v-for="(popup, index) in popupList" v-if="popup.visible" :key="index" class="popup-component" :class="'popup-component--' + positionMap[popup.position]"> 16 <div @click.stop v-if="popup.position == 'right_bottom' || popup.position == 'right_top'" class="toast" :class="'toast--' + popup.style"> 17 <span v-if="!!popup.is_close" class="close" @click="closePopup(popup)"> 18 <svg width="14" height="14" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> 19 <path d="M11 1L1 11" stroke="white" stroke-linecap="round" stroke-linejoin="round" /> 20 <path d="M1 1L11 11" stroke="white" stroke-linecap="round" stroke-linejoin="round" /> 21 </svg> 22 </span> 23 <p>{{popup.text}}</p> 24 <a v-if="popup.buttons" v-for="(item, index) in popup.buttons" @click="onButtonClick(popup, item)" :href="item.link" :class="{'outline': index == 1}" :key="index"> 25 {{item.text}} 26 </a> 27 </div> 28 29 <div @click.stop v-if="popup.position == 'center'" class="modal" :class="{'modal--html': popup.video}"> 30 <span v-if="!!popup.is_close" class="close" @click="closePopup(popup)"> 31 <svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"> 32 <path d="M11 1L1 11" :stroke="popup.image ? 'white' : '#342F37'" stroke-linecap="round" stroke-linejoin="round" /> 33 <path d="M1 1L11 11" :stroke="popup.image ? 'white' : '#342F37'" stroke-linecap="round" stroke-linejoin="round" /> 34 </svg> 35 </span> 36 <img v-if="popup.image && popup.image.length > 0" :src="popup.image" /> 37 <div class="modal__body"> 38 <h2>{{popup.title}}</h2> 39 <p v-html="popup.text"></p> 40 41 <div class="questions" v-for="(question, index) in popup.questions" :key="index"> 42 <p>{{question.title}}</p> 43 <div v-if="question.type == 'text'"> 44 <textarea v-model="popup.answers[question.id]" type="text" :id="'input-' + question.id" /> 45 </div> 46 <div v-if="question.type == 'rating'" class="star-rating"> 47 <label class="star" v-for="rating in ratingArray" :class="{'is-selected': popup.answers[question.id] >= rating}"> 48 <input class="checkbox" type="radio" :value="rating" v-model="popup.answers[question.id]"> 49 <span> 50 <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> 51 <circle cx="8" cy="8" r="8" fill="#EBE7EF" /> 52 </svg> 53 </span> 54 </label> 55 </div> 56 </div> 57 </div> 58 <div class="modal__footer" v-if="popup.buttons"> 59 <a v-for="(item, index) in popup.buttons" @click="onButtonClick(popup, item)" :href="item.link" :class="{'outline': index == 1}" :key="index"> 60 {{item.text}} 61 </a> 62 </div> 63 <div v-if="popup.video" class="modal__footer"> 64 <iframe :src="popup.video" frameborder="0" width="100%" height="315"></iframe> 65 </div> 66 </div> 67 68 <div v-if="popup.position == 'top' || popup.position == 'bottom'" class="alert" :class="'alert--' + popup.style"> 69 <p v-html="popup.text"></p> 70 <a v-if="popup.buttons" 71 v-for="(item, index) in popup.buttons" @click="onButtonClick(popup, item)" :href="item.link" :class="{'outline': index == 1}" :key="index"> 72 {{item.text}} 73 </a> 74 </div> 75 </div> 76 </div> 77 `, 78 data () { 79 return { 80 isClosed: false, 81 positionMap: { 82 'bottom': 'cb', 83 'left': 'cc', 84 'right': 'cc', 85 'center': 'cc', 86 'right_bottom': 'br', 87 'right_top': 'tr', 88 'top': 'ct', 89 }, 90 popupList: [], 91 apiURL: '', 92 answers: {}, 93 failureCount: 0, 94 ratingArray: [1,2,3,4,5,6,7,8,9,10], 95 pathname: '', 96 } 97 }, 98 created () { 99 this.apiURL = this.fetchPath() 100 this.loadPopupConfig() 101 102 this.pathname = window.location.href; 103 setInterval(() => { 104 if (window.location.href != this.pathname) { 105 // console.log('updatePopups'); 106 this.pathname = window.location.href; 107 this.loadPopupConfig() 108 } 109 }, 1000); 110 111 }, 112 computed: { 113 getPopupBlackout () { 114 return this.popupList.filter(popup => { 115 return popup.blackout == 1 && popup.visible 116 }).length > 0 117 } 118 }, 119 methods: { 120 fetchPath () { 121 let _location = window.location.href; 122 123 if (_location.includes('local') || _location.includes('dev')) { 124 return 'https://test-popups.k8.u2035dev.ru' 125 } else if (_location.includes('test')) { 126 return 'https://test-popups.k8.u2035dev.ru' 127 } else if (_location.includes('stage')) { 128 return 'https://stage-popups.k8.u2035dev.ru' 129 } else if (_location.includes('university')) { 130 return 'https://popup.2035.university' 131 } else { 132 return 'https://test-popups.k8.u2035dev.ru' 133 } 134 }, 135 sendReaction (type, popup, buttonText = null) { 136 let answers = [], 137 formData = new FormData() 138 139 Object.keys(popup.answers).map(question_id => { 140 answers.push({ 141 question_id: question_id, 142 answer: popup.answers[question_id] 143 }) 144 }) 145 146 if (type != 'show') { 147 formData.append('answers', JSON.stringify(answers)) 148 formData.append('button', buttonText) 149 } 150 formData.append('value', 1) 151 152 153 this.axios('POST', `/api/v1/popup/${popup.tracker_uuid}/${type}`, null, formData).then(response => { 154 console.log('send reaction', type, popup.tracker_uuid); 155 }).catch(error => { 156 console.error('POST', ' /api/v1/popup/{id}/{type}: ', error) 157 }) 158 }, 159 axios (type, url, query = null, formData = null) { 160 return new Promise((resolve, reject) => { 161 let _query = new URLSearchParams(this.cleanObj(query)) 162 163 if (query) { 164 fetch(`${this.apiURL + url}?${_query}`, { 165 method: type 166 }) 167 .then(response => resolve(response.json())) 168 .catch(error => reject(error)) 169 } else { 170 fetch(`${this.apiURL + url}`, { 171 method: type, 172 body: formData 173 }) 174 .then(response => resolve(response.json())) 175 .catch(error => reject(error)) 176 } 177 178 }) 179 }, 180 cleanObj (obj) { 181 for (var propName in obj) { 182 if (obj[propName] === null || obj[propName] === undefined) { 183 delete obj[propName]; 184 } 185 } 186 return obj 187 }, 188 closePopup (popup) { 189 console.log('popup closed'); 190 this.sendReaction('close', popup) 191 popup.visible = false;
192 }, 193 onButtonClick (popup, button) { 194 this.sendReaction('reaction', popup, button.text) 195 console.log('button click'); 196 }, 197 uuidv4() { 198 var d = new Date().getTime(); 199 var d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported 200 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 201 var r = Math.random() * 16;//random number between 0 and 16 202 if(d > 0){//Use timestamp until depleted 203 r = (d + r)%16 | 0; 204 d = Math.floor(d/16); 205 } else {//Use microseconds since page-load if supported 206 r = (d2 + r)%16 | 0; 207 d2 = Math.floor(d2/16); 208 } 209 return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); 210 }); 211 212 }, 213 loadPopupConfig () { 214 if (window.dataLayer && window.dataLayer.length > 0) { 215 216 let unti_id, guest_id, context; 217 window.dataLayer.map(layer => { 218 if ( layer['unti_id'] ) { 219 unti_id = layer['unti_id'] 220 } 221 if ( layer['context'] ) { 222 context = layer['context'] 223 } 224 }) 225 let _cookies = document.cookie.split(';').map(cookie => { 226 return { 227 [cookie.split('=')[0].replace(' ', '')]: cookie.split('=')[1] 228 } 229 }) 230 231 let hasCookie = false 232 _cookies.map(cookie => { 233 if (Object.keys(cookie) == 'guest_id') { 234 guest_id = Object.values(cookie) 235 hasCookie = true 236 } 237 }) 238 239 if (!hasCookie) { 240 let date = new Date(Date.now() + 86400e3 * 365); 241 date = date.toUTCString(); 242 243 guest_id = this.uuidv4() 244 document.cookie = "guest_id=" + guest_id + "; expires=" + date 245 } 246 247 this.axios('POST', '/api/v1/popups', { 248 url: window.location.href, 249 screen: window.innerWidth < 600 ? 'mobile' : 'desktop', 250 unti_id: unti_id || null, 251 guest_id: guest_id || null, 252 context: context || null, 253 }).then(response => { 254 255 // let _response = { 256 // "result": { 257 // "successful": true, 258 // "code": 200 259 // }, 260 // "payload": [ 261 // { 262 // "id": "dc7ca2fe-01d7-4431-ac99-d89dc00784a5", 263 // "title": "rrrrrrrrrrrrr", 264 // "text": "rrrrrrr", 265 // "url": "", 266 // "image": "", 267 // "video": "", 268 // "button": "", 269 // "show_button": 0, 270 // "position": "center", 271 // "screen": "desktop", 272 // "style": "white", 273 // "blackout": 0, 274 // "is_close": 0, 275 // "tracker_uuid": "4e76659e-b825-461f-99f4-d179729ee57e", 276 // "questions": [] 277 // } 278 // ] 279 // } 280 this.popupList = Object.values(response.payload) 281 282 283 if (this.popupList.length > 0) { 284 this.popupList.map(popup => { 285 this.$set(popup, 'visible', true); 286 this.$set(popup, 'answers', {}); 287 288 if (!!popup.show_button && popup.button.length > 0) { 289 this.$set(popup, 'buttons', JSON.parse(popup.button)); 290 } 291 292 popup.questions.map(question => { 293 this.$set(popup.answers, question.id, null); 294 }) 295 296 // if (!!popup.is_close == false) { 297 this.sendReaction('show', popup); 298 // } 299 }) 300 } 301 }).catch(error => { 302 console.error('POST', '/api/v1/popups: ', error) 303 }) 304 } else { 305 this.failureCount++ 306 if (this.failureCount < 3) { 307 setTimeout(() => { 308 console.log('await for window.dataLayer'); 309 this.loadPopupConfig() 310 }, 2000) 311 } else { 312 console.warn('unable to await window.dataLayer, aborting fetch...') 313 } 314 315 } 316 317 } 318 } 319 }); 320 321 new Vue({ 322 el: '#popups', 323 }) 324 325}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.