PageSourceSearch

https://robclouth.com/js/web.js

js robclouth.com collected 2026-10-08 18:55:23 UTC 13,111 bytes, 463 lines download raw bytes

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.