From d8e0a67278923a70af37a8ffcf5e1997c6ea2ae2 Mon Sep 17 00:00:00 2001 From: Sagnik Ganguly Date: Sat, 21 Jan 2023 17:46:29 +0530 Subject: [PATCH] ADDED: Addon: SGNFullPage: It will allow the user to scroll whole page. --- demos/addons/fullpage.html | 61 ++++ demos/atom.index.html | 7 + demos/index.html | 1 + src/addons/SGNFullPage/SGNFullPage.css | 143 ++++++++ src/addons/SGNFullPage/SGNFullPage.js | 479 +++++++++++++++++++++++++ src/addons/addons.css | 3 +- src/addons/addons.js | 1 + src/js/SGNUIKit.loader.js | 46 ++- 8 files changed, 726 insertions(+), 15 deletions(-) create mode 100644 demos/addons/fullpage.html create mode 100644 src/addons/SGNFullPage/SGNFullPage.css create mode 100644 src/addons/SGNFullPage/SGNFullPage.js diff --git a/demos/addons/fullpage.html b/demos/addons/fullpage.html new file mode 100644 index 00000000..08288906 --- /dev/null +++ b/demos/addons/fullpage.html @@ -0,0 +1,61 @@ + + + + + + + FullPage Addon - SGNUIKit Demo + + + + + +
+
+
Section-1
+
+
Slide 1
+
Slide 2
+
Slide 3
+
+
Section-3
+
+
Slide 1
+
Slide 2
+
Slide 3
+
+
+
+ + + diff --git a/demos/atom.index.html b/demos/atom.index.html index 4a38e329..ea70791f 100644 --- a/demos/atom.index.html +++ b/demos/atom.index.html @@ -42,6 +42,13 @@ Shadows +
+
Addons
+ +
diff --git a/demos/index.html b/demos/index.html index 8f9eb503..c20336b3 100644 --- a/demos/index.html +++ b/demos/index.html @@ -48,6 +48,7 @@
Addons
SGNAtom + fullPage.js
diff --git a/src/addons/SGNFullPage/SGNFullPage.css b/src/addons/SGNFullPage/SGNFullPage.css new file mode 100644 index 00000000..cb7e7795 --- /dev/null +++ b/src/addons/SGNFullPage/SGNFullPage.css @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 SGNetworks. All rights reserved. + * + * The software is an exclusive copyright of "SGNetworks" and is provided as is exclusively with only "USAGE" access. "Modification", "Alteration", "Re-distribution" is completely prohibited. + * VIOLATING THE ABOVE TERMS IS A PUNISHABLE OFFENSE WHICH MAY LEAD TO LEGAL CONSEQUENCES. + */ + +.sgn-fullpage *, +.sgn-fullpage-active * { + --sgn-fp-nav-color: var(--sgn-accent-primary-text, hsl(0, 0%, 100%)); + --sgn-fp-nav-active-color: var(var(--sgn-fp-nav-color), var(--sgn-accent-primary-active)); + --sgn-fp-nav-size: 4px; + --sgn-fp-nav-active-size: 12px; +} + +.sgn-fullpage, +.sgn-fullpage > section, +.sgn-fullpage > .section { + height: 100vh; +} + +.sgn-fullpage { + +} + +.sgn-fullpage > section.sgn-fp-slides, +.sgn-fullpage > .section.sgn-fp-slides { + display: flex; + justify-content: start; + align-items: center; + width: 100%; + position: relative; + overflow: auto; + scrollbar-width: none !important; +} + +.sgn-fullpage > section.sgn-fp-slides > .slide, +.sgn-fullpage > .section.sgn-fp-slides > .slide { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + flex: 1 0 100%; +} + +.sgn-fp-nav { + display: flex; + justify-content: center; + position: absolute; + margin: 0; +} + +.sgn-fp-nav > li, +.sgn-fp-nav > li > a { + width: var(--sgn-fp-nav-size); + height: var(--sgn-fp-nav-size); + position: relative; + z-index: 1; + line-height: 1; + text-decoration: none; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; +} + +.sgn-fp-nav > li { + list-style: none; +} + +.sgn-fp-nav > li > a { + width: 100%; + height: 100%; +} + +.sgn-fp-nav > li.active { + width: var(--sgn-fp-nav-active-size); + height: var(--sgn-fp-nav-active-size); +} + +.sgn-fp-nav > li > a > i { + content: ""; + width: var(--sgn-fp-nav-size); + height: var(--sgn-fp-nav-size); + border-radius: 100%; + background: var(--sgn-fp-nav-color); + transition: width, height .1s ease-out; +} + +.sgn-fp-nav > li.active > a > i { + width: var(--sgn-fp-nav-active-size); + height: var(--sgn-fp-nav-active-size); + transition: width, height .2s ease-in; +} + +.sgn-fp-nav.nav-top, +.sgn-fp-nav.nav-bottom { + flex-direction: row; + align-items: center; + margin: 1rem 0; + width: 100%; +} + +.sgn-fp-nav.nav-top > li, +.sgn-fp-nav.nav-bottom > li { + margin: 0 .5rem; +} + +.sgn-fp-nav.nav-left > li, +.sgn-fp-nav.nav-right > li { + justify-content: center; + align-items: center; + display: flex; + margin: .5rem 0; +} + +.sgn-fp-nav.nav-top { + top: 0; +} + +.sgn-fp-nav.nav-bottom { + bottom: 0; +} + +.sgn-fp-nav.nav-left, +.sgn-fp-nav.nav-right { + flex-direction: column; + align-items: center; + top: 0; + bottom: 0; + margin: 0 1rem; + height: 100%; +} + +.sgn-fp-nav.nav-left { + left: 0; +} + +.sgn-fp-nav.nav-right { + right: 0; +} + diff --git a/src/addons/SGNFullPage/SGNFullPage.js b/src/addons/SGNFullPage/SGNFullPage.js new file mode 100644 index 00000000..024119f7 --- /dev/null +++ b/src/addons/SGNFullPage/SGNFullPage.js @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2023 SGNetworks. All rights reserved. + * + * The software is an exclusive copyright of "SGNetworks" and is provided as is exclusively with only "USAGE" access. "Modification", "Alteration", "Re-distribution" is completely prohibited. + * VIOLATING THE ABOVE TERMS IS A PUNISHABLE OFFENSE WHICH MAY LEAD TO LEGAL CONSEQUENCES. + */ + +"use strict"; // Start of use strict +if(typeof jQuery === "undefined") { + throw new Error("SGNFullPage requires jQuery"); +} + +;(function(window, document, $) { + "use strict"; + + /*** + * + * @param {jQuery | HTMLElement} $fullpage + * @param {{scroll_speed: number, transition_speed: number, default_page: number, delta_threshold: number, page_indicator: boolean, slider_indicator: boolean, scroll_indicator: boolean}} [options={}] + * + * @return {SGNFullPage} + * + * @constructor + */ + const SGNFullPage = function($fullpage, options = {}) { + const plugin = this; + const _defaults = { + 'scroll_indicator': true, + 'page_indicator': true, + 'slider_indicator': true, + 'delta_threshold': 1, + 'scroll_speed': 1000, + 'transition_speed': 1000, + 'default_page': 1 + }; + plugin.settings = {}; + const $body = $('body'), + $main = $body.children('main'), + $sections = $($fullpage).children('.section, section'); + let maxPages, currentPage, currentSlide; + let $pageNav, $slideNav; + + const GUID = str => { + if(str === undefined || !str.length) + str = "" + Math.random() * new Date().getTime() + Math.random(); + + let c = 0, + r = ""; + + for(let i = 0; i < str.length; i++) + c = (c + (str.charCodeAt(i) * (i + 1) - 1)) & 0xfffffffffffff; + + str = str.substr(str.length / 2) + c.toString(16) + str.substr(0, str.length / 2); + for(let i = 0, p = c + str.length; i < 32; i++) { + if(i === 8 || i === 12 || i === 16 || i === 20) + r += "-"; + + c = p = (str[(i ** i + p + 1) % str.length]).charCodeAt(0) + p + i; + if(i === 12) + c = (c % 5) + 1; //1-5 + else if(i === 16) + c = (c % 4) + 8; //8-B + else + c %= 16; //0-F + + r += c.toString(16); + } + return r; + }; + + const init = () => { + $.extend(plugin.settings, _defaults, options); + + if(!$body.hasClass('sgn-fullpage-active')) + $body.addClass('sgn-fullpage-active'); + + maxPages = $sections.length; + + const defaultPage = plugin.settings.default_page; + currentPage = ($.isNumeric(defaultPage) && defaultPage > 0 && defaultPage <= maxPages) ? defaultPage : 1; + plugin.settings.default_page = currentPage; + + if(maxPages > 0) { + let navLinksHTML; + $sections.each(function(i) { + const j = (i + 1), + $this = $(this), + $section = $this, + $slides = $this.children('.slide'); + + const activeClass = (j === plugin.settings.default_page) ? 'active' : '', + id = $this.attr('id') || GUID(), + title = $this.attr('title') || `Page-${j}`; + + $this.attr({'id': id, 'title': title}); + + if(j === plugin.settings.default_page && !$this.hasClass('active')) + $this.addClass('active'); + + const navLinkTitleHTML = `${title}`, + navLinkHTML = `
  • ${navLinkTitleHTML}
  • `; + + if(navLinksHTML === undefined) + navLinksHTML = navLinkHTML; + else + navLinksHTML += navLinkHTML; + + $slides.each(function(i) { + const j = (i + 1), + $this = $(this); + const currentSlide = 1; + const id = $this.attr('id') || GUID(), + title = $this.attr('title') || `Slide-${j}`; + + $this.attr({'id': id, 'title': title}); + + if(j === currentSlide && !$this.hasClass('active')) + $this.addClass('active'); + + if(!$section.hasClass('sgn-fp-slides')) + $section.addClass('sgn-fp-slides'); + }); + }); + + const navHTML = (navLinksHTML !== undefined) ? `` : undefined; + + if(navHTML !== undefined) { + $body.append(navHTML); + $pageNav = $body.children('.sgn-fp-nav.page-nav'); + } + + bindEvents(); + } + }; + + const initSlides = ($section, $slides) => { + let slideNavLinksHTML; + + $slides.each(function(i) { + const j = (i + 1), + $this = $(this); + const $activeSlide = $section.children('.slide.active'); + const activeSlideIndex = ($activeSlide.length > 0) ? $activeSlide.index() : 1; + currentSlide = activeSlideIndex + 1; + + const activeClass = (j === currentSlide) ? 'active' : '', + id = $this.attr('id') || GUID(), + title = $this.attr('title') || `Slide-${j}`; + + const slideNavLinkTitleHTML = `${title}`, + slideNavLinkHTML = `
  • ${slideNavLinkTitleHTML}
  • `; + + if(slideNavLinksHTML === undefined) + slideNavLinksHTML = slideNavLinkHTML; + else + slideNavLinksHTML += slideNavLinkHTML; + }); + + const slideNavHTML = (slideNavLinksHTML !== undefined) ? `` : undefined; + + if($slideNav !== undefined && $slideNav.length > 0) + $slideNav.remove(); + + if(slideNavHTML !== undefined && ($slideNav === undefined || $slideNav.length <= 0)) { + $body.append(slideNavHTML); + $slideNav = $body.children('.sgn-fp-nav.slide-nav').fadeOut(0).fadeIn(plugin.settings.transition_speed); + } + + if(!$section.hasClass('sgn-fp-slides')) + $section.addClass('sgn-fp-slides'); + + bindEvents.bindSlideScroll($section, $slides); + }; + + const bindEvents = () => { + let isSlideActive = false, slideDown = false, slideUp = false, allowPageUp = true, allowPageDown = true; + let isPageScrolling = false; + + bindEvents.bindSlideScroll = ($section, $slides) => { + const maxSlides = $slides.length; + currentSlide = ($.isNumeric(currentSlide)) ? currentSlide : 1; + + allowPageUp = ($section.prev('section, .section').length > 0); + allowPageDown = ($section.next('section, .section').length > 0); + if(currentSlide === maxSlides) { + slideUp = true; + allowPageUp = false; + slideDown = ($section.next('section, .section').length > 0); + allowPageDown = true; + } else if(currentSlide === 1) { + slideDown = true; + allowPageDown = false; + slideUp = ($section.prev('section, .section').length > 0); + allowPageUp = true; + } else { + slideUp = slideUp = true; + allowPageUp = allowPageDown = false; + } + + isSlideActive = (slideUp || slideDown); + + $section.off('wheel'); + $section.on('wheel', function(e) { + e.preventDefault(); + + if(!isSlideActive) + return; + + if(currentSlide === maxSlides) { + slideUp = true; + allowPageUp = false; + slideDown = ($section.next('section, .section').length > 0); + allowPageDown = true; + } else if(currentSlide === 1) { + slideDown = true; + allowPageDown = false; + slideUp = ($section.prev('section, .section').length > 0); + allowPageUp = true; + } else { + slideUp = slideUp = true; + allowPageUp = allowPageDown = false; + } + + isSlideActive = (slideUp || slideDown); + + let t, i, delay = false; + + if(delay) return; + + delay = true; + setTimeout(() => delay = false, 200); + + const wd = e.wheelDelta || -e.detail; + let wheelYPositive; + if(wd < 0) { + wheelYPositive = true; + for(i = 0; i < maxSlides; i++) { + t = $slides[i].getClientRects()[0].left; + if(t >= plugin.settings.delta_threshold) + break; + } + } else { + wheelYPositive = false; + for(i = maxSlides - 1; i >= 0; i--) { + t = $slides[i].getClientRects()[0].left; + if(t <= -plugin.settings.delta_threshold) + break; + } + } + + if(!slideDown && wheelYPositive) + return; + else if(!slideUp && !wheelYPositive) + return; + + if(i >= 0 && i < maxSlides) { + isPageScrolling = true; + $slides.removeClass('active'); + + const slide = $slides[i], + $slide = $(slide); + const distance = slide.offsetLeft; + + $section.stop().val(0).animate({ + scrollLeft: distance + }, plugin.settings.scroll_speed, function() { + const $this = $(this); + currentSlide = (i + 1); + //$this.data('current-slide', currentSlide); + + allowPageUp = ($section.prev('section, .section').length > 0); + allowPageDown = ($section.next('section, .section').length > 0); + + if(currentSlide === maxSlides) { + slideUp = true; + allowPageUp = false; + slideDown = ($section.next('section, .section').length > 0); + allowPageDown = true; + } else if(currentSlide === 1) { + slideDown = true; + allowPageDown = false; + slideUp = ($section.prev('section, .section').length > 0); + allowPageUp = true; + } else { + slideUp = slideUp = true; + allowPageUp = allowPageDown = false; + } + + isSlideActive = (slideUp || slideDown); + //console.log(isSlideActive, slideDown, slideUp, wheelYPositive); + + $slideNav.children('li').removeClass('active'); + $($slideNav.children('li')[i]).addClass('active'); + $slide.addClass('active'); + + isPageScrolling = false; + }); + } + }); + } + + const bindPageScroll = () => { + $(document).on('wheel', function(e) { + e.preventDefault(); + if(isPageScrolling) + return; + + if(!isSlideActive) { + allowPageUp = allowPageDown = true; + } + + let t, i, delay = false; + + if(delay) + return; + + delay = true; + setTimeout(() => delay = false, 200); + + const wd = e.wheelDelta || -e.detail; + let wheelYPositive; + if(wd < 0) { + wheelYPositive = true; + for(i = 0; i < $sections.length; i++) { + t = $sections[i].getClientRects()[0].top; + if(t >= plugin.settings.delta_threshold) + break; + } + } else { + wheelYPositive = false; + for(i = $sections.length - 1; i >= 0; i--) { + t = $sections[i].getClientRects()[0].top; + if(t <= -plugin.settings.delta_threshold) + break; + } + } + //console.log(isSlideActive, allowPageDown, allowPageUp, wheelYPositive); + + if(!allowPageDown && wheelYPositive) + return; + else if(!allowPageUp && !wheelYPositive) + return; + + if(i >= 0 && i < $sections.length) { + $sections.removeClass('active'); + + const section = $sections[i], + $section = $(section); + const distance = section.offsetTop; + + isPageScrolling = true; + $main.stop().val(0).animate({ + scrollTop: distance + }, plugin.settings.scroll_speed, function() { + const $this = $(this); + currentPage = (i + 1); + $pageNav.children('li').removeClass('active'); + $($pageNav.children('li')[i]).addClass('active'); + $section.addClass('active'); + + const $slides = $section.children('.slide'); + if($slides.length > 0) { + initSlides($section, $slides); + } else { + isSlideActive = slideUp = slideDown = false; + allowPageUp = allowPageDown = true; + if($slideNav !== undefined && $slideNav.length > 0) { + $slideNav.fadeOut(plugin.settings.transition_speed, () => { + $slideNav.remove(); + $slideNav = undefined; + }); + } + } + + isPageScrolling = false; + }); + } + }); + }; + + const bindNavigationEvents = () => { + if($pageNav !== undefined && $pageNav.length > 0) { + const $lists = $pageNav.children('li'); + $lists.children('a').on('click', function() { + //e.preventDefault(); + const $this = $(this), + $li = $this.parent('li'), + nth = $li.index(); + currentPage = (nth + 1); + + const $currentPage = $($sections[nth]); + + $lists.removeClass('active'); + $li.addClass('active'); + + $sections.removeClass('active'); + $currentPage.addClass('active'); + + const $slides = $currentPage.children('.slide'); + if($slides.length > 0) { + initSlides($currentPage, $slides); + } else { + isSlideActive = slideUp = slideDown = false; + allowPageUp = allowPageDown = true; + if($slideNav !== undefined && $slideNav.length > 0) { + $slideNav.fadeOut(plugin.settings.transition_speed, () => { + $slideNav.remove(); + $slideNav = undefined; + }); + } + } + }); + } + + if($slideNav !== undefined && $slideNav.length > 0) { + const $lists = $slideNav.children('li'); + $lists.children('a').on('click', function() { + //e.preventDefault(); + const $this = $(this), + $li = $this.parent('li'), + nth = $li.index(); + currentSlide = (nth + 1); + + $lists.removeClass('active'); + $li.addClass('active'); + }); + } + }; + + bindPageScroll(); + bindNavigationEvents(); + + //return bindEvents; + }; + + init(); + + return plugin; + }; + + /*** + * Creates a SGNFullPage object with the supplied options. + * + * @param options + * + * @return {jQuery.SGNFullPage} + * + * @constructor + */ + $.fn.SGNFullPage = function(options = { + 'scroll_indicator': true, + 'page_indicator': true, + 'slider_indicator': true, + 'delta_threshold': 1, + 'scroll_speed': 1000, + 'transition_speed': 1000, + 'default_page': 1 + }) { + const _this = this, + $_this = $(_this); + + const plugin = new SGNFullPage($_this, options); + + return _this; + }; + + $(function() { + const $fullpages = $(".sgn-fullpage"); + + if($fullpages.length > 0) { + $fullpages.each(function() { + const $this = $(this); + $this.SGNFullPage(); + }); + } + }); + + return this; +})(window, document, jQuery); diff --git a/src/addons/addons.css b/src/addons/addons.css index 729c7c45..8ffcd6ff 100644 --- a/src/addons/addons.css +++ b/src/addons/addons.css @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 SGNetworks. All rights reserved. + * Copyright (c) 2022-2023 SGNetworks. All rights reserved. * * The software is an exclusive copyright of "SGNetworks" and is provided as is exclusively with only "USAGE" access. "Modification", "Alteration", "Re-distribution" is completely prohibited. * VIOLATING THE ABOVE TERMS IS A PUNISHABLE OFFENSE WHICH MAY LEAD TO LEGAL CONSEQUENCES. @@ -16,6 +16,7 @@ @import "noty/themes/relax.css" all and (prefers-color-scheme: light); @import "noty/themes/metroui.css" all and (prefers-color-scheme: dark); @import "PrismJS/prism.css"; +@import "SGNFullPage/SGNFullPage.css"; @import "SGNTimePicker/SGNTimePicker.min.css" all and (prefers-color-scheme: light); @import "SweetAlert2/sweetalert2.min.css"; diff --git a/src/addons/addons.js b/src/addons/addons.js index 611600b2..57ab356f 100644 --- a/src/addons/addons.js +++ b/src/addons/addons.js @@ -21,6 +21,7 @@ import('./noty/noty.js'); import("./noty/noty.init.js"); import("./PrismJS/prism.js"); import("./SGNAtom/SGNAtom.js"); +import("./SGNFullPage/SGNFullPage.js"); import("./SGNGeoData/SGNGeoData.js"); import('./SGNTimePicker/SGNTimePicker.js'); import('./SweetAlert2/sweetalert2.all.js'); diff --git a/src/js/SGNUIKit.loader.js b/src/js/SGNUIKit.loader.js index a09dc9e9..8a7d9ffd 100644 --- a/src/js/SGNUIKit.loader.js +++ b/src/js/SGNUIKit.loader.js @@ -2480,6 +2480,7 @@ body { "addons/noty/noty.init.js", "addons/PrismJS/prism.js", "addons/SGNAtom/SGNAtom.js", + "addons/SGNFullPage/SGNFullPage.js", "addons/SGNGeoData/SGNGeoData.js", "addons/SGNTimePicker/SGNTimePicker.js", "addons/SweetAlert2/sweetalert2.all.js", @@ -2560,23 +2561,40 @@ body { if(left !== null) left.parentNode.removeChild(left); - setTimeout(function() { - $.holdReady(false); - jQuery.ready(); - SGNUIKit.setOnChangeListener((prop, value) => { - if(prop === 'holdPreloader' && !value) { - const $body = $("body"); + /*setTimeout(function() { + $.holdReady(false); + jQuery.ready(); + }, 5000);*/ + } - $body.children(".sgn-preloader").fadeOut(2000, function() { - $body.children(".sgn-preloader").remove(); - $body.removeClass("has-preloader"); - }); - } - }); - }, 5000); - } + SGNUIKit.setOnChangeListener((prop, value) => { + const $body = $("body"); + + if(prop === 'holdPreloader') { + if(!value) { + $.holdReady(false); + jQuery.ready(); + + $body.children(".sgn-preloader").fadeOut(2000, function() { + $body.children(".sgn-preloader").remove(); + $body.removeClass("has-preloader"); + }); + } + } else { + if(prop === 'ready' && !SGNUIKit.holdPreloader) { + //console.log(prop, value); + $.holdReady(false); + jQuery.ready(); + + $body.children(".sgn-preloader").fadeOut(2000, function() { + $body.children(".sgn-preloader").remove(); + $body.removeClass("has-preloader"); + }); + } + } + }); }); });