1class Website { 2 constructor() { 3 this.$content = null; 4 this.$scrollElem = null; 5 this.$divsWithBlurredBackgrounds = null; 6 this.$mediaPopup = null; 7 this.$particleVideo = null; 8 this.width = null; 9 this.sectionHeight = null; 10 11 this.projects = []; 12 this.tags = []; 13 this.filters = []; 14 15 this.moreInfoFadeTime = 250; 16 this.loadedImages = false; 17 18 this.blurImageW = 1500; 19 this.blurImageH = 1000; 20 this.projectsNumRows = 3; 21 22 this.$content = $("#content"); 23 this.$scrollElem = $("body"); 24 25 this.particles = new Particles(); 26 } 27 28 setupParticles = options => { 29 const diffusedImage = Math.floor(Math.random() * 7) + 2; 30 if (jQuery.browser.mobile || !Detector.webgl) { 31 const videoHtml = ` 32 <video loop autoplay muted id="particleVideo"> 33 <source src="/videos/particles${Math.floor( 34 Math.random() * 8 + 1 35 )}.mp4" type="video/mp4"> 36 </video> 37 `; 38 $("#home-section").append(videoHtml); 39 this.$particleVideo = $("#particleVideo"); 40 } else { 41 $.ajax({ 42 type: "GET", 43 url: "/images/diffuser/" + diffusedImage + ".js", 44 contentType: "application/text; charset=utf-8", 45 dataType: "text", 46 success: data => { 47 this.particles.init($("#particleCanvas")[0], data, 450, 450, options); 48 }, 49 error: error => {} 50 }); 51 } 52 }; 53 54 setupMainSite = () => { 55 this.projects = content.projects.filter(project => project); 56 this.createProjectSlides(this.projects, "#projects-section"); 57 this.createIndex(); 58 this.initFullPage(); 59 this.resize(); 60 }; 61 62 setupLibrariesAndEventsListeners = () => { 63 Galleria.run(".media", { 64 transition: "fade", 65 imageCrop: false, 66 swipe: "true", 67 clicknext: "true", 68 showImagenav: false, 69 imageMargin: 50, 70 wait: true, 71 showCounter: false, 72 thumbnails: "lazy", 73 youtube: { enablejsapi: 1 } 74 }); 75 76 Pace.on("hide", () => { 77 $("#loadingScreen").fadeOut(500); 78 }); 79 80 $(".backgroundImage").on("load", e => { 81 $(e.currentTarget).fadeIn(); 82 }); 83 84 $(".mediaButton").click(e => { 85 this.openPopup($(e.currentTarget)); 86 }); 87 88 $(".mediaPopup .closeButton").click(() => { 89 this.closePopup(); 90 }); 91 }; 92 93 createProjectSlides = (projects, containerSelector) => { 94 // build content 95 for (const project of projects) { 96 const audioClipsHtml = project.audioClips 97 ? `<div class='audioClips'> 98 ${project.audioClips 99 .map(audioClip => { 100 return `<a href='${audioClip.url}'>${audioClip.description}</a>`; 101 }) 102 .join("")} 103 </div>` 104 : ""; 105 106 const tagsHtml = project.tags 107 .map(tag => { 108 return `<div class='tag'>${tag}</div>`; 109 }) 110 .join(""); 111 112 const mediaHtml = project.media 113 ? `<div class='mediaPopup' style="background-image: url('/images/${ 114 project.backgroundImage 115 }-1500px-blur.jpg')"> 116 <div class='media'> 117 ${project.media 118 .map(mediaItem => { 119 return `<a href="${mediaItem.url}"><img src="${mediaItem.thumb}"></a>`; 120 }) 121 .join("")} 122 </div> 123 <div class='closeButton'/> 124 </div>` 125 : ""; 126 127 const buttonsHtml = project.buttons 128 ? project.buttons 129 .map(button => { 130 return `<a href="${button.url}" class="bigButton" currentTarget="_blank">${button.text}</a>`; 131 }) 132 .join("") 133 : ""; 134 135 const html = `<div data-anchor='${project.id}' class='slide'>" 136 <img data-src='/images/${ 137 project.backgroundImage 138 }-1500px-blur.jpg' class='blurredBackgroundImage'> 139 <img data-src='/images/${ 140 project.backgroundImage 141 }-1500px.jpg' class='backgroundImage'> 142 <div class='slideHeaders'> 143 <h1 class='slideTitle'>${project.name}</h1> 144 <h2 class='slideSubtitle'>${project.detail}</h2> 145 <div class='tags'> 146 ${tagsHtml} 147 </div> 148 </div> 149 <div class='slideDescription'> 150 <p>${project.description}</p> 151 ${audioClipsHtml} 152 <div> 153 ${project.media ? "<div class='mediaButton'>Media</div>" : ""} 154 ${buttonsHtml} 155 </div> 156 </div> 157 ${mediaHtml} 158 </div> 159 `; 160 161 $(containerSelector).append(html); 162 } 163
164 this.$divsWithBlurredBackgrounds = $( 165 ".slideHeaders h1, .slideHeaders h2, .slideDescription, .tag" 166 ); 167 }; 168 169 initFullPage = options => { 170 this.fullpage = new fullpage("#content", { 171 licenseKey: "E0D715A0-8AAC4D18-910F93E2-884E4DB0", 172 //Navigation 173 lockAnchors: false, 174 //Scrolling 175 css3: true, 176 scrollingSpeed: 300, 177 autoScrolling: true, 178 fitToSection: true, 179 fitToSectionDelay: 200, 180 scrollBar: false, 181 easing: "easeInOutCubic", 182 easingcss3: "ease", 183 loopBottom: false, 184 loopTop: false, 185 loopHorizontal: false, 186 continuousVertical: false, 187 normalScrollElements: "#element1, .element2", 188 scrollOverflow: false, 189 touchSensitivity: 15, 190 normalScrollElementTouchThreshold: 5, 191 navigation: true, 192 navigationPosition: "right", 193 navigationTooltips: ["Home", "Index", "Projects", "About"], 194 showActiveTooltip: false, 195 slidesNavigation: true, 196 slidesNavPosition: "bottom", 197 //Accessibility 198 keyboardScrolling: true, 199 animateAnchor: true, 200 recordHistory: true, 201 202 //Design 203 controlArrows: false, 204 verticalCentered: false, 205 resize: false, 206 //paddingBottom: '40px', 207 responsiveWidth: 0, 208 responsiveHeight: 0, 209 dragAndMove: false, 210 dragAndMoveKey: "cm9iY2xvdXRoLmNvbV8xaDRaSEpoWjBGdVpFMXZkbVU9UzlH", 211 212 //events 213 onLeave: (index, nextIndex, direction) => { 214 this.closePopup(); 215 }, 216 afterLoad: (origin, destination) => { 217 if (destination.index !== 0) { 218 $("#fp-nav span").removeClass("dark"); 219 220 this.stopParticles(); 221 this.loadImages(); 222 } else if (destination.index == 0) { 223 $("#fp-nav span").addClass("dark"); 224 this.startParticles(); 225 } 226 }, 227 onSlideLeave: ( 228 anchorLink, 229 index, 230 slideIndex, 231 direction, 232 nextSlideIndex 233 ) => { 234 const $nextSectionSlide = $("#projects-section .fp-slide ").eq( 235 nextSlideIndex 236 ); 237 this.loadSlideBackground($nextSectionSlide); 238 239 if (direction === "right" && $nextSectionSlide.next().length > 0) { 240 this.loadSlideBackground($nextSectionSlide.next()); 241 } else if ( 242 direction === "left" && 243 $nextSectionSlide.prev().length > 0 244 ) { 245 this.loadSlideBackground($nextSectionSlide.prev()); 246 } 247 }, 248 ...options 249 }); 250 }; 251 252 loadImages() { 253 if (!this.loadedImages) { 254 const $blurredImages = $(".blurredBackgroundImage"); 255 $blurredImages.each((i, blurredImage) => { 256 $(blurredImage).attr("src", $(blurredImage).attr("data-src")); 257 }); 258 this.resize(); 259 this.loadedImages = true; 260 } 261 } 262 263 loadSlideBackground = $slide => { 264 const $image = $slide.find(".backgroundImage"); 265 $image.attr("src", $image.attr("data-src")); 266 }; 267 268 startParticles() { 269 this.particles.start(); 270 this.$particleVideo && this.$particleVideo[0].play(); 271 } 272 273 stopParticles() { 274 this.particles.stop(); 275 this.$particleVideo && this.$particleVideo[0].pause(); 276 } 277 278 openPopup = $slide => { 279 this.$mediaPopup = $slide.parentsUntil(".project").siblings(".mediaPopup"); 280 this.$mediaPopup.css("display", "block"); 281 this.$mediaPopup.transition( 282 { 283 opacity: 1 284 }, 285 this.moreInfoFadeTime 286 ); 287 288 this.fullpage.setAllowScrolling(false, "left, right"); 289 $(".fp-slidesNav").fadeOut(this.moreInfoFadeTime); 290 $("#gridViewButton").fadeOut(this.moreInfoFadeTime); 291 }; 292 293 closePopup() { 294 if (!this.$mediaPopup) return; 295 296 this.$mediaPopup.transition( 297 { 298 opacity: 0 299 }, 300 this.moreInfoFadeTime, 301 () => { 302 this.$mediaPopup.css("display", "none"); 303 } 304 ); 305 306 // if normal video 307 let videoElem = this.$mediaPopup.find("video")[0]; 308 if (videoElem) videoElem.pause(); 309 310 //if youtube 311 videoElem = this.$mediaPopup.find("iframe")[0]; 312 if (videoElem && videoElem.contentWindow) 313 videoElem.contentWindow.postMessage( 314 '{"event":"command","func":"' + "stopVideo" + '","args":""}', 315 "*" 316 ); 317 318 //if vimeo 319 const vimeoFrame = this.$mediaPopup.find("iframe[src*='vimeo']")[0]; 320 if (vimeoFrame) { 321 const player = new Vimeo.Player(vimeoFrame); 322 player.unload(); 323 } 324 325 this.fullpage.setAllowScrolling(true, "left, right");
326 $(".fp-slidesNav").fadeIn(this.moreInfoFadeTime); 327 $("#gridViewButton").fadeIn(this.moreInfoFadeTime); 328 } 329 330 createIndex = () => { 331 const $index = $("#index-section"); 332 const numPerPage = jQuery.browser.mobile 333 ? 2 * this.projectsNumRows 334 : 4 * this.projectsNumRows; 335 336 let $gridPage; 337 $(this.projects).each((i, project) => { 338 if (i % numPerPage === 0) { 339 if ($gridPage !== undefined) $index.append($gridPage); 340 $gridPage = $("<div class='gridPage slide'></div>"); 341 } 342 343 const projectTitle = project.name; 344 const projectSubTitle = project.detail; 345 346 const thumbImageUrl = `images/${project.backgroundImage}-500px.jpg`; 347 const blurredThumbImageUrl = `images/${project.backgroundImage}-500px-blur.jpg`; 348 349 const itemTags = []; 350 for (let tag of project.tags) { 351 const $gridtag = $("<div class='gridTag'>" + tag + "</div>"); 352 //$gridtag.css("background-image", "url(" + blurredThumbImageUrl + ")"); 353 itemTags.push($gridtag); 354 } 355 const $gridItem = $("<div class='gridItem'></div>"); 356
357 const $gridItemBackground = $( 358 `<img class="gridItemBackground" data-src="${thumbImageUrl}"></img>` 359 ); 360 361 // $gridItemBackground.css("background-image", "url(" + thumbImageUrl + ")"); 362 const $gridItemBackgroundBlurred = $( 363 "<div class='gridItemBackgroundBlurred'></div>" 364 ); 365 $gridItemBackground.on("load", () => { 366 $gridItemBackgroundBlurred.fadeOut(); 367 }); 368 369 $gridItemBackgroundBlurred.css( 370 "background-image", 371 "url(" + blurredThumbImageUrl + ")" 372 ); 373 374 const $gridItemTitle = $( 375 "<div><h1 class='gridItemTitle'>" + projectTitle + "</h1></div>" 376 ); 377 const $gridItemSubTitle = $( 378 "<div><h2 class='gridItemSubtitle'>" + projectSubTitle + "</h2></div>" 379 ); 380 const $gridItemTags = $("<div class='gridTags'></div>"); 381 382 $gridItemTags.append(itemTags); 383 $gridItem.append($gridItemBackground); 384 $gridItem.append($gridItemBackgroundBlurred); 385 $gridItem.append($gridItemTitle); 386 $gridItem.append($gridItemSubTitle); 387 $gridItem.append($gridItemTags); 388 $gridItem.hover( 389 e => { 390 $(e.currentTarget)
391 .children(".gridItemBackgroundBlurred") 392 .fadeIn(150); 393 }, 394 e => { 395 $(e.currentTarget) 396 .children(".gridItemBackgroundBlurred") 397 .fadeOut(150); 398 } 399 ); 400 401 $gridItem.click(() => this.fullpage.moveTo("projects", project.id)); 402 403 $gridPage.append($gridItem); 404 }); 405 406 $index.append($gridPage); 407 }; 408 409 resize = () => { 410 this.width = $("#content").width(); 411 this.sectionHeight = $("#content").height(); 412 413 this.$divsWithBlurredBackgrounds.each((i, elem) => { 414 this.setBlurredBackground($(elem)); 415 }); 416 }; 417 418 updateTransparency = $slide => { 419 const $elemsToBlur = $slide.find( 420 ".slideHeaders h1, .slideHeaders h2, .slideDescription, .tag, .textBlock" 421 ); 422 $elemsToBlur.each((i, elem) => { 423 this.setBlurredBackground($(elem)); 424 }); 425 }; 426 427 setBlurredBackground = $elem => { 428 const $parent = $elem.closest(".slide, .section"); 429 const $blurredBackgroundImage = $parent.find( 430 ".blurredBackgroundImage:first" 431 ); 432 433 const elemOffsetX = $elem.offset().left - $parent.offset().left; 434 const elemOffsetY = $elem.offset().top - $parent.offset().top; 435 436 let backgroundOffsetX = 0; 437 let backgroundOffsetY = 0; 438 let imgW, imgH; 439 const ratio = this.blurImageW / this.blurImageH; 440 if (this.width / this.sectionHeight > ratio) { 441 imgW = this.width; 442 imgH = this.width / ratio; 443 backgroundOffsetY = -(imgH - this.sectionHeight) / 2; 444 } else { 445 imgW = this.sectionHeight * ratio; 446 imgH = this.sectionHeight; 447 backgroundOffsetX = -(imgW - this.width) / 2; 448 } 449 450 let url = $blurredBackgroundImage.attr("src"); 451 if (!url) url = $blurredBackgroundImage.attr("data-src"); 452 $elem.css("background", "url('" + url + "')"); 453 $elem.css("background-size", imgW + "px " + imgH + "px"); 454 $elem.css( 455 "background-position", 456 -elemOffsetX + 457 backgroundOffsetX + 458 "px " + 459 (-elemOffsetY + backgroundOffsetY) + 460 "px" 461 ); 462 }; 463}
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.