');
+ }
+
+ item.inlineElement = el;
+ return el;
+ }
+
+ mfp.updateStatus('ready');
+ mfp._parseMarkup(template, {}, item);
+ return template;
+ }
+ }
+});
+
+/*>>inline*/
+
+/*>>ajax*/
+var AJAX_NS = 'ajax',
+ _ajaxCur,
+ _removeAjaxCursor = function() {
+ if(_ajaxCur) {
+ $(document.body).removeClass(_ajaxCur);
+ }
+ },
+ _destroyAjaxRequest = function() {
+ _removeAjaxCursor();
+ if(mfp.req) {
+ mfp.req.abort();
+ }
+ };
+
+$.magnificPopup.registerModule(AJAX_NS, {
+
+ options: {
+ settings: null,
+ cursor: 'mfp-ajax-cur',
+ tError: '
The content could not be loaded.'
+ },
+
+ proto: {
+ initAjax: function() {
+ mfp.types.push(AJAX_NS);
+ _ajaxCur = mfp.st.ajax.cursor;
+
+ _mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
+ _mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
+ },
+ getAjax: function(item) {
+
+ if(_ajaxCur) {
+ $(document.body).addClass(_ajaxCur);
+ }
+
+ mfp.updateStatus('loading');
+
+ var opts = $.extend({
+ url: item.src,
+ success: function(data, textStatus, jqXHR) {
+ var temp = {
+ data:data,
+ xhr:jqXHR
+ };
+
+ _mfpTrigger('ParseAjax', temp);
+
+ mfp.appendContent( $(temp.data), AJAX_NS );
+
+ item.finished = true;
+
+ _removeAjaxCursor();
+
+ mfp._setFocus();
+
+ setTimeout(function() {
+ mfp.wrap.addClass(READY_CLASS);
+ }, 16);
+
+ mfp.updateStatus('ready');
+
+ _mfpTrigger('AjaxContentAdded');
+ },
+ error: function() {
+ _removeAjaxCursor();
+ item.finished = item.loadError = true;
+ mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
+ }
+ }, mfp.st.ajax.settings);
+
+ mfp.req = $.ajax(opts);
+
+ return '';
+ }
+ }
+});
+
+/*>>ajax*/
+
+/*>>image*/
+var _imgInterval,
+ _getTitle = function(item) {
+ if(item.data && item.data.title !== undefined)
+ return item.data.title;
+
+ var src = mfp.st.image.titleSrc;
+
+ if(src) {
+ if($.isFunction(src)) {
+ return src.call(mfp, item);
+ } else if(item.el) {
+ return item.el.attr(src) || '';
+ }
+ }
+ return '';
+ };
+
+$.magnificPopup.registerModule('image', {
+
+ options: {
+ markup: '
',
+ cursor: 'mfp-zoom-out-cur',
+ titleSrc: 'title',
+ verticalFit: true,
+ tError: '
The image could not be loaded.'
+ },
+
+ proto: {
+ initImage: function() {
+ var imgSt = mfp.st.image,
+ ns = '.image';
+
+ mfp.types.push('image');
+
+ _mfpOn(OPEN_EVENT+ns, function() {
+ if(mfp.currItem.type === 'image' && imgSt.cursor) {
+ $(document.body).addClass(imgSt.cursor);
+ }
+ });
+
+ _mfpOn(CLOSE_EVENT+ns, function() {
+ if(imgSt.cursor) {
+ $(document.body).removeClass(imgSt.cursor);
+ }
+ _window.off('resize' + EVENT_NS);
+ });
+
+ _mfpOn('Resize'+ns, mfp.resizeImage);
+ if(mfp.isLowIE) {
+ _mfpOn('AfterChange', mfp.resizeImage);
+ }
+ },
+ resizeImage: function() {
+ var item = mfp.currItem;
+ if(!item || !item.img) return;
+
+ if(mfp.st.image.verticalFit) {
+ var decr = 0;
+ // fix box-sizing in ie7/8
+ if(mfp.isLowIE) {
+ decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
+ }
+ item.img.css('max-height', mfp.wH-decr);
+ }
+ },
+ _onImageHasSize: function(item) {
+ if(item.img) {
+
+ item.hasSize = true;
+
+ if(_imgInterval) {
+ clearInterval(_imgInterval);
+ }
+
+ item.isCheckingImgSize = false;
+
+ _mfpTrigger('ImageHasSize', item);
+
+ if(item.imgHidden) {
+ if(mfp.content)
+ mfp.content.removeClass('mfp-loading');
+
+ item.imgHidden = false;
+ }
+
+ }
+ },
+
+ /**
+ * Function that loops until the image has size to display elements that rely on it asap
+ */
+ findImageSize: function(item) {
+
+ var counter = 0,
+ img = item.img[0],
+ mfpSetInterval = function(delay) {
+
+ if(_imgInterval) {
+ clearInterval(_imgInterval);
+ }
+ // decelerating interval that checks for size of an image
+ _imgInterval = setInterval(function() {
+ if(img.naturalWidth > 0) {
+ mfp._onImageHasSize(item);
+ return;
+ }
+
+ if(counter > 200) {
+ clearInterval(_imgInterval);
+ }
+
+ counter++;
+ if(counter === 3) {
+ mfpSetInterval(10);
+ } else if(counter === 40) {
+ mfpSetInterval(50);
+ } else if(counter === 100) {
+ mfpSetInterval(500);
+ }
+ }, delay);
+ };
+
+ mfpSetInterval(1);
+ },
+
+ getImage: function(item, template) {
+
+ var guard = 0,
+
+ // image load complete handler
+ onLoadComplete = function() {
+ if(item) {
+ if (item.img[0].complete) {
+ item.img.off('.mfploader');
+
+ if(item === mfp.currItem){
+ mfp._onImageHasSize(item);
+
+ mfp.updateStatus('ready');
+ }
+
+ item.hasSize = true;
+ item.loaded = true;
+
+ _mfpTrigger('ImageLoadComplete');
+
+ }
+ else {
+ // if image complete check fails 200 times (20 sec), we assume that there was an error.
+ guard++;
+ if(guard < 200) {
+ setTimeout(onLoadComplete,100);
+ } else {
+ onLoadError();
+ }
+ }
+ }
+ },
+
+ // image error handler
+ onLoadError = function() {
+ if(item) {
+ item.img.off('.mfploader');
+ if(item === mfp.currItem){
+ mfp._onImageHasSize(item);
+ mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
+ }
+
+ item.hasSize = true;
+ item.loaded = true;
+ item.loadError = true;
+ }
+ },
+ imgSt = mfp.st.image;
+
+
+ var el = template.find('.mfp-img');
+ if(el.length) {
+ var img = document.createElement('img');
+ img.className = 'mfp-img';
+ if(item.el && item.el.find('img').length) {
+ img.alt = item.el.find('img').attr('alt');
+ }
+ item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
+ img.src = item.src;
+
+ // without clone() "error" event is not firing when IMG is replaced by new IMG
+ // TODO: find a way to avoid such cloning
+ if(el.is('img')) {
+ item.img = item.img.clone();
+ }
+
+ img = item.img[0];
+ if(img.naturalWidth > 0) {
+ item.hasSize = true;
+ } else if(!img.width) {
+ item.hasSize = false;
+ }
+ }
+
+ mfp._parseMarkup(template, {
+ title: _getTitle(item),
+ img_replaceWith: item.img
+ }, item);
+
+ mfp.resizeImage();
+
+ if(item.hasSize) {
+ if(_imgInterval) clearInterval(_imgInterval);
+
+ if(item.loadError) {
+ template.addClass('mfp-loading');
+ mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
+ } else {
+ template.removeClass('mfp-loading');
+ mfp.updateStatus('ready');
+ }
+ return template;
+ }
+
+ mfp.updateStatus('loading');
+ item.loading = true;
+
+ if(!item.hasSize) {
+ item.imgHidden = true;
+ template.addClass('mfp-loading');
+ mfp.findImageSize(item);
+ }
+
+ return template;
+ }
+ }
+});
+
+/*>>image*/
+
+/*>>zoom*/
+var hasMozTransform,
+ getHasMozTransform = function() {
+ if(hasMozTransform === undefined) {
+ hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
+ }
+ return hasMozTransform;
+ };
+
+$.magnificPopup.registerModule('zoom', {
+
+ options: {
+ enabled: false,
+ easing: 'ease-in-out',
+ duration: 300,
+ opener: function(element) {
+ return element.is('img') ? element : element.find('img');
+ }
+ },
+
+ proto: {
+
+ initZoom: function() {
+ var zoomSt = mfp.st.zoom,
+ ns = '.zoom',
+ image;
+
+ if(!zoomSt.enabled || !mfp.supportsTransition) {
+ return;
+ }
+
+ var duration = zoomSt.duration,
+ getElToAnimate = function(image) {
+ var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
+ transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
+ cssObj = {
+ position: 'fixed',
+ zIndex: 9999,
+ left: 0,
+ top: 0,
+ '-webkit-backface-visibility': 'hidden'
+ },
+ t = 'transition';
+
+ cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;
+
+ newImg.css(cssObj);
+ return newImg;
+ },
+ showMainContent = function() {
+ mfp.content.css('visibility', 'visible');
+ },
+ openTimeout,
+ animatedImg;
+
+ _mfpOn('BuildControls'+ns, function() {
+ if(mfp._allowZoom()) {
+
+ clearTimeout(openTimeout);
+ mfp.content.css('visibility', 'hidden');
+
+ // Basically, all code below does is clones existing image, puts in on top of the current one and animated it
+
+ image = mfp._getItemToZoom();
+
+ if(!image) {
+ showMainContent();
+ return;
+ }
+
+ animatedImg = getElToAnimate(image);
+
+ animatedImg.css( mfp._getOffset() );
+
+ mfp.wrap.append(animatedImg);
+
+ openTimeout = setTimeout(function() {
+ animatedImg.css( mfp._getOffset( true ) );
+ openTimeout = setTimeout(function() {
+
+ showMainContent();
+
+ setTimeout(function() {
+ animatedImg.remove();
+ image = animatedImg = null;
+ _mfpTrigger('ZoomAnimationEnded');
+ }, 16); // avoid blink when switching images
+
+ }, duration); // this timeout equals animation duration
+
+ }, 16); // by adding this timeout we avoid short glitch at the beginning of animation
+
+
+ // Lots of timeouts...
+ }
+ });
+ _mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
+ if(mfp._allowZoom()) {
+
+ clearTimeout(openTimeout);
+
+ mfp.st.removalDelay = duration;
+
+ if(!image) {
+ image = mfp._getItemToZoom();
+ if(!image) {
+ return;
+ }
+ animatedImg = getElToAnimate(image);
+ }
+
+ animatedImg.css( mfp._getOffset(true) );
+ mfp.wrap.append(animatedImg);
+ mfp.content.css('visibility', 'hidden');
+
+ setTimeout(function() {
+ animatedImg.css( mfp._getOffset() );
+ }, 16);
+ }
+
+ });
+
+ _mfpOn(CLOSE_EVENT+ns, function() {
+ if(mfp._allowZoom()) {
+ showMainContent();
+ if(animatedImg) {
+ animatedImg.remove();
+ }
+ image = null;
+ }
+ });
+ },
+
+ _allowZoom: function() {
+ return mfp.currItem.type === 'image';
+ },
+
+ _getItemToZoom: function() {
+ if(mfp.currItem.hasSize) {
+ return mfp.currItem.img;
+ } else {
+ return false;
+ }
+ },
+
+ // Get element postion relative to viewport
+ _getOffset: function(isLarge) {
+ var el;
+ if(isLarge) {
+ el = mfp.currItem.img;
+ } else {
+ el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
+ }
+
+ var offset = el.offset();
+ var paddingTop = parseInt(el.css('padding-top'),10);
+ var paddingBottom = parseInt(el.css('padding-bottom'),10);
+ offset.top -= ( $(window).scrollTop() - paddingTop );
+
+
+ /*
+
+ Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.
+
+ */
+ var obj = {
+ width: el.width(),
+ // fix Zepto height+padding issue
+ height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
+ };
+
+ // I hate to do this, but there is no another option
+ if( getHasMozTransform() ) {
+ obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
+ } else {
+ obj.left = offset.left;
+ obj.top = offset.top;
+ }
+ return obj;
+ }
+
+ }
+});
+
+
+
+/*>>zoom*/
+
+/*>>iframe*/
+
+var IFRAME_NS = 'iframe',
+ _emptyPage = '//about:blank',
+
+ _fixIframeBugs = function(isShowing) {
+ if(mfp.currTemplate[IFRAME_NS]) {
+ var el = mfp.currTemplate[IFRAME_NS].find('iframe');
+ if(el.length) {
+ // reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
+ if(!isShowing) {
+ el[0].src = _emptyPage;
+ }
+
+ // IE8 black screen bug fix
+ if(mfp.isIE8) {
+ el.css('display', isShowing ? 'block' : 'none');
+ }
+ }
+ }
+ };
+
+$.magnificPopup.registerModule(IFRAME_NS, {
+
+ options: {
+ markup: '
',
+
+ srcAction: 'iframe_src',
+
+ // we don't care and support only one default type of URL by default
+ patterns: {
+ youtube: {
+ index: 'youtube.com',
+ id: 'v=',
+ src: '//www.youtube.com/embed/%id%?autoplay=1'
+ },
+ vimeo: {
+ index: 'vimeo.com/',
+ id: '/',
+ src: '//player.vimeo.com/video/%id%?autoplay=1'
+ },
+ gmaps: {
+ index: '//maps.google.',
+ src: '%id%&output=embed'
+ }
+ }
+ },
+
+ proto: {
+ initIframe: function() {
+ mfp.types.push(IFRAME_NS);
+
+ _mfpOn('BeforeChange', function(e, prevType, newType) {
+ if(prevType !== newType) {
+ if(prevType === IFRAME_NS) {
+ _fixIframeBugs(); // iframe if removed
+ } else if(newType === IFRAME_NS) {
+ _fixIframeBugs(true); // iframe is showing
+ }
+ }// else {
+ // iframe source is switched, don't do anything
+ //}
+ });
+
+ _mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
+ _fixIframeBugs();
+ });
+ },
+
+ getIframe: function(item, template) {
+ var embedSrc = item.src;
+ var iframeSt = mfp.st.iframe;
+
+ $.each(iframeSt.patterns, function() {
+ if(embedSrc.indexOf( this.index ) > -1) {
+ if(this.id) {
+ if(typeof this.id === 'string') {
+ embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
+ } else {
+ embedSrc = this.id.call( this, embedSrc );
+ }
+ }
+ embedSrc = this.src.replace('%id%', embedSrc );
+ return false; // break;
+ }
+ });
+
+ var dataObj = {};
+ if(iframeSt.srcAction) {
+ dataObj[iframeSt.srcAction] = embedSrc;
+ }
+ mfp._parseMarkup(template, dataObj, item);
+
+ mfp.updateStatus('ready');
+
+ return template;
+ }
+ }
+});
+
+
+
+/*>>iframe*/
+
+/*>>gallery*/
+/**
+ * Get looped index depending on number of slides
+ */
+var _getLoopedId = function(index) {
+ var numSlides = mfp.items.length;
+ if(index > numSlides - 1) {
+ return index - numSlides;
+ } else if(index < 0) {
+ return numSlides + index;
+ }
+ return index;
+ },
+ _replaceCurrTotal = function(text, curr, total) {
+ return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
+ };
+
+$.magnificPopup.registerModule('gallery', {
+
+ options: {
+ enabled: false,
+ arrowMarkup: '
',
+ preload: [0,2],
+ navigateByImgClick: true,
+ arrows: true,
+
+ tPrev: 'Previous (Left arrow key)',
+ tNext: 'Next (Right arrow key)',
+ tCounter: '%curr% of %total%'
+ },
+
+ proto: {
+ initGallery: function() {
+
+ var gSt = mfp.st.gallery,
+ ns = '.mfp-gallery';
+
+ mfp.direction = true; // true - next, false - prev
+
+ if(!gSt || !gSt.enabled ) return false;
+
+ _wrapClasses += ' mfp-gallery';
+
+ _mfpOn(OPEN_EVENT+ns, function() {
+
+ if(gSt.navigateByImgClick) {
+ mfp.wrap.on('click'+ns, '.mfp-img', function() {
+ if(mfp.items.length > 1) {
+ mfp.next();
+ return false;
+ }
+ });
+ }
+
+ _document.on('keydown'+ns, function(e) {
+ if (e.keyCode === 37) {
+ mfp.prev();
+ } else if (e.keyCode === 39) {
+ mfp.next();
+ }
+ });
+ });
+
+ _mfpOn('UpdateStatus'+ns, function(e, data) {
+ if(data.text) {
+ data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
+ }
+ });
+
+ _mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
+ var l = mfp.items.length;
+ values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
+ });
+
+ _mfpOn('BuildControls' + ns, function() {
+ if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
+ var markup = gSt.arrowMarkup,
+ arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),
+ arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);
+
+ arrowLeft.click(function() {
+ mfp.prev();
+ });
+ arrowRight.click(function() {
+ mfp.next();
+ });
+
+ mfp.container.append(arrowLeft.add(arrowRight));
+ }
+ });
+
+ _mfpOn(CHANGE_EVENT+ns, function() {
+ if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);
+
+ mfp._preloadTimeout = setTimeout(function() {
+ mfp.preloadNearbyImages();
+ mfp._preloadTimeout = null;
+ }, 16);
+ });
+
+
+ _mfpOn(CLOSE_EVENT+ns, function() {
+ _document.off(ns);
+ mfp.wrap.off('click'+ns);
+ mfp.arrowRight = mfp.arrowLeft = null;
+ });
+
+ },
+ next: function() {
+ mfp.direction = true;
+ mfp.index = _getLoopedId(mfp.index + 1);
+ mfp.updateItemHTML();
+ },
+ prev: function() {
+ mfp.direction = false;
+ mfp.index = _getLoopedId(mfp.index - 1);
+ mfp.updateItemHTML();
+ },
+ goTo: function(newIndex) {
+ mfp.direction = (newIndex >= mfp.index);
+ mfp.index = newIndex;
+ mfp.updateItemHTML();
+ },
+ preloadNearbyImages: function() {
+ var p = mfp.st.gallery.preload,
+ preloadBefore = Math.min(p[0], mfp.items.length),
+ preloadAfter = Math.min(p[1], mfp.items.length),
+ i;
+
+ for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
+ mfp._preloadItem(mfp.index+i);
+ }
+ for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
+ mfp._preloadItem(mfp.index-i);
+ }
+ },
+ _preloadItem: function(index) {
+ index = _getLoopedId(index);
+
+ if(mfp.items[index].preloaded) {
+ return;
+ }
+
+ var item = mfp.items[index];
+ if(!item.parsed) {
+ item = mfp.parseEl( index );
+ }
+
+ _mfpTrigger('LazyLoad', item);
+
+ if(item.type === 'image') {
+ item.img = $('
![]()
').on('load.mfploader', function() {
+ item.hasSize = true;
+ }).on('error.mfploader', function() {
+ item.hasSize = true;
+ item.loadError = true;
+ _mfpTrigger('LazyLoadError', item);
+ }).attr('src', item.src);
+ }
+
+
+ item.preloaded = true;
+ }
+ }
+});
+
+/*>>gallery*/
+
+/*>>retina*/
+
+var RETINA_NS = 'retina';
+
+$.magnificPopup.registerModule(RETINA_NS, {
+ options: {
+ replaceSrc: function(item) {
+ return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
+ },
+ ratio: 1 // Function or number. Set to 1 to disable.
+ },
+ proto: {
+ initRetina: function() {
+ if(window.devicePixelRatio > 1) {
+
+ var st = mfp.st.retina,
+ ratio = st.ratio;
+
+ ratio = !isNaN(ratio) ? ratio : ratio();
+
+ if(ratio > 1) {
+ _mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
+ item.img.css({
+ 'max-width': item.img[0].naturalWidth / ratio,
+ 'width': '100%'
+ });
+ });
+ _mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
+ item.src = st.replaceSrc(item, ratio);
+ });
+ }
+ }
+
+ }
+ }
+});
+
+/*>>retina*/
+ _checkInstance(); }));
\ No newline at end of file
diff --git a/public/assets/homepage/js/vendors/jquery.magnific-popup.js:Zone.Identifier b/public/assets/homepage/js/vendors/jquery.magnific-popup.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/jquery.magnific-popup.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/jquery.mcustomscrollbar.concat.min.js b/public/assets/homepage/js/vendors/jquery.mcustomscrollbar.concat.min.js
new file mode 100644
index 0000000..51cb729
--- /dev/null
+++ b/public/assets/homepage/js/vendors/jquery.mcustomscrollbar.concat.min.js
@@ -0,0 +1,16 @@
+/*
+Custom scrollbar - jquery mousewheel plugin
+Version: 3.1.13
+Plugin URI: http://manos.malihu.gr/jquery-custom-content-scroller
+License: Copyright Manos Malihutsakis | Released under the MIT license
+*/
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
+
+/*
+Custom scrollbar - malihu jquery custom scrollbar plugin
+Version: 3.1.5
+Plugin URI: http://manos.malihu.gr/jquery-custom-content-scroller
+License: Copyright Manos Malihutsakis | Released under the MIT license
+*/
+!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"undefined"!=typeof module&&module.exports?module.exports=e:e(jQuery,window,document)}(function(e){!function(t){var o="function"==typeof define&&define.amd,a="undefined"!=typeof module&&module.exports,n="https:"==document.location.protocol?"https:":"http:",i="cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js";o||(a?require("jquery-mousewheel")(e):e.event.special.mousewheel||e("head").append(decodeURI("%3Cscript src="+n+"//"+i+"%3E%3C/script%3E"))),t()}(function(){var t,o="mCustomScrollbar",a="mCS",n=".mCustomScrollbar",i={setTop:0,setLeft:0,axis:"y",scrollbarPosition:"inside",scrollInertia:950,autoDraggerLength:!0,alwaysShowScrollbar:0,snapOffset:0,mouseWheel:{enable:!0,scrollAmount:"auto",axis:"y",deltaFactor:"auto",disableOver:["select","option","keygen","datalist","textarea"]},scrollButtons:{scrollType:"stepless",scrollAmount:"auto"},keyboard:{enable:!0,scrollType:"stepless",scrollAmount:"auto"},contentTouchScroll:25,documentTouchScroll:!0,advanced:{autoScrollOnFocus:"input,textarea,select,button,datalist,keygen,a[tabindex],area,object,[contenteditable='true']",updateOnContentResize:!0,updateOnImageLoad:"auto",autoUpdateTimeout:60},theme:"light",callbacks:{onTotalScrollOffset:0,onTotalScrollBackOffset:0,alwaysTriggerOffsets:!0}},r=0,l={},s=window.attachEvent&&!window.addEventListener?1:0,c=!1,d=["mCSB_dragger_onDrag","mCSB_scrollTools_onDrag","mCS_img_loaded","mCS_disabled","mCS_destroyed","mCS_no_scrollbar","mCS-autoHide","mCS-dir-rtl","mCS_no_scrollbar_y","mCS_no_scrollbar_x","mCS_y_hidden","mCS_x_hidden","mCSB_draggerContainer","mCSB_buttonUp","mCSB_buttonDown","mCSB_buttonLeft","mCSB_buttonRight"],u={init:function(t){var t=e.extend(!0,{},i,t),o=f.call(this);if(t.live){var s=t.liveSelector||this.selector||n,c=e(s);if("off"===t.live)return void m(s);l[s]=setTimeout(function(){c.mCustomScrollbar(t),"once"===t.live&&c.length&&m(s)},500)}else m(s);return t.setWidth=t.set_width?t.set_width:t.setWidth,t.setHeight=t.set_height?t.set_height:t.setHeight,t.axis=t.horizontalScroll?"x":p(t.axis),t.scrollInertia=t.scrollInertia>0&&t.scrollInertia<17?17:t.scrollInertia,"object"!=typeof t.mouseWheel&&1==t.mouseWheel&&(t.mouseWheel={enable:!0,scrollAmount:"auto",axis:"y",preventDefault:!1,deltaFactor:"auto",normalizeDelta:!1,invert:!1}),t.mouseWheel.scrollAmount=t.mouseWheelPixels?t.mouseWheelPixels:t.mouseWheel.scrollAmount,t.mouseWheel.normalizeDelta=t.advanced.normalizeMouseWheelDelta?t.advanced.normalizeMouseWheelDelta:t.mouseWheel.normalizeDelta,t.scrollButtons.scrollType=g(t.scrollButtons.scrollType),h(t),e(o).each(function(){var o=e(this);if(!o.data(a)){o.data(a,{idx:++r,opt:t,scrollRatio:{y:null,x:null},overflowed:null,contentReset:{y:null,x:null},bindEvents:!1,tweenRunning:!1,sequential:{},langDir:o.css("direction"),cbOffsets:null,trigger:null,poll:{size:{o:0,n:0},img:{o:0,n:0},change:{o:0,n:0}}});var n=o.data(a),i=n.opt,l=o.data("mcs-axis"),s=o.data("mcs-scrollbar-position"),c=o.data("mcs-theme");l&&(i.axis=l),s&&(i.scrollbarPosition=s),c&&(i.theme=c,h(i)),v.call(this),n&&i.callbacks.onCreate&&"function"==typeof i.callbacks.onCreate&&i.callbacks.onCreate.call(this),e("#mCSB_"+n.idx+"_container img:not(."+d[2]+")").addClass(d[2]),u.update.call(null,o)}})},update:function(t,o){var n=t||f.call(this);return e(n).each(function(){var t=e(this);if(t.data(a)){var n=t.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container"),l=e("#mCSB_"+n.idx),s=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];if(!r.length)return;n.tweenRunning&&Q(t),o&&n&&i.callbacks.onBeforeUpdate&&"function"==typeof i.callbacks.onBeforeUpdate&&i.callbacks.onBeforeUpdate.call(this),t.hasClass(d[3])&&t.removeClass(d[3]),t.hasClass(d[4])&&t.removeClass(d[4]),l.css("max-height","none"),l.height()!==t.height()&&l.css("max-height",t.height()),_.call(this),"y"===i.axis||i.advanced.autoExpandHorizontalScroll||r.css("width",x(r)),n.overflowed=y.call(this),M.call(this),i.autoDraggerLength&&S.call(this),b.call(this),T.call(this);var c=[Math.abs(r[0].offsetTop),Math.abs(r[0].offsetLeft)];"x"!==i.axis&&(n.overflowed[0]?s[0].height()>s[0].parent().height()?B.call(this):(G(t,c[0].toString(),{dir:"y",dur:0,overwrite:"none"}),n.contentReset.y=null):(B.call(this),"y"===i.axis?k.call(this):"yx"===i.axis&&n.overflowed[1]&&G(t,c[1].toString(),{dir:"x",dur:0,overwrite:"none"}))),"y"!==i.axis&&(n.overflowed[1]?s[1].width()>s[1].parent().width()?B.call(this):(G(t,c[1].toString(),{dir:"x",dur:0,overwrite:"none"}),n.contentReset.x=null):(B.call(this),"x"===i.axis?k.call(this):"yx"===i.axis&&n.overflowed[0]&&G(t,c[0].toString(),{dir:"y",dur:0,overwrite:"none"}))),o&&n&&(2===o&&i.callbacks.onImageLoad&&"function"==typeof i.callbacks.onImageLoad?i.callbacks.onImageLoad.call(this):3===o&&i.callbacks.onSelectorChange&&"function"==typeof i.callbacks.onSelectorChange?i.callbacks.onSelectorChange.call(this):i.callbacks.onUpdate&&"function"==typeof i.callbacks.onUpdate&&i.callbacks.onUpdate.call(this)),N.call(this)}})},scrollTo:function(t,o){if("undefined"!=typeof t&&null!=t){var n=f.call(this);return e(n).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l={trigger:"external",scrollInertia:r.scrollInertia,scrollEasing:"mcsEaseInOut",moveDragger:!1,timeout:60,callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},s=e.extend(!0,{},l,o),c=Y.call(this,t),d=s.scrollInertia>0&&s.scrollInertia<17?17:s.scrollInertia;c[0]=X.call(this,c[0],"y"),c[1]=X.call(this,c[1],"x"),s.moveDragger&&(c[0]*=i.scrollRatio.y,c[1]*=i.scrollRatio.x),s.dur=ne()?0:d,setTimeout(function(){null!==c[0]&&"undefined"!=typeof c[0]&&"x"!==r.axis&&i.overflowed[0]&&(s.dir="y",s.overwrite="all",G(n,c[0].toString(),s)),null!==c[1]&&"undefined"!=typeof c[1]&&"y"!==r.axis&&i.overflowed[1]&&(s.dir="x",s.overwrite="none",G(n,c[1].toString(),s))},s.timeout)}})}},stop:function(){var t=f.call(this);return e(t).each(function(){var t=e(this);t.data(a)&&Q(t)})},disable:function(t){var o=f.call(this);return e(o).each(function(){var o=e(this);if(o.data(a)){o.data(a);N.call(this,"remove"),k.call(this),t&&B.call(this),M.call(this,!0),o.addClass(d[3])}})},destroy:function(){var t=f.call(this);return e(t).each(function(){var n=e(this);if(n.data(a)){var i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx),s=e("#mCSB_"+i.idx+"_container"),c=e(".mCSB_"+i.idx+"_scrollbar");r.live&&m(r.liveSelector||e(t).selector),N.call(this,"remove"),k.call(this),B.call(this),n.removeData(a),$(this,"mcs"),c.remove(),s.find("img."+d[2]).removeClass(d[2]),l.replaceWith(s.contents()),n.removeClass(o+" _"+a+"_"+i.idx+" "+d[6]+" "+d[7]+" "+d[5]+" "+d[3]).addClass(d[4])}})}},f=function(){return"object"!=typeof e(this)||e(this).length<1?n:this},h=function(t){var o=["rounded","rounded-dark","rounded-dots","rounded-dots-dark"],a=["rounded-dots","rounded-dots-dark","3d","3d-dark","3d-thick","3d-thick-dark","inset","inset-dark","inset-2","inset-2-dark","inset-3","inset-3-dark"],n=["minimal","minimal-dark"],i=["minimal","minimal-dark"],r=["minimal","minimal-dark"];t.autoDraggerLength=e.inArray(t.theme,o)>-1?!1:t.autoDraggerLength,t.autoExpandScrollbar=e.inArray(t.theme,a)>-1?!1:t.autoExpandScrollbar,t.scrollButtons.enable=e.inArray(t.theme,n)>-1?!1:t.scrollButtons.enable,t.autoHideScrollbar=e.inArray(t.theme,i)>-1?!0:t.autoHideScrollbar,t.scrollbarPosition=e.inArray(t.theme,r)>-1?"outside":t.scrollbarPosition},m=function(e){l[e]&&(clearTimeout(l[e]),$(l,e))},p=function(e){return"yx"===e||"xy"===e||"auto"===e?"yx":"x"===e||"horizontal"===e?"x":"y"},g=function(e){return"stepped"===e||"pixels"===e||"step"===e||"click"===e?"stepped":"stepless"},v=function(){var t=e(this),n=t.data(a),i=n.opt,r=i.autoExpandScrollbar?" "+d[1]+"_expand":"",l=["
","
"],s="yx"===i.axis?"mCSB_vertical_horizontal":"x"===i.axis?"mCSB_horizontal":"mCSB_vertical",c="yx"===i.axis?l[0]+l[1]:"x"===i.axis?l[1]:l[0],u="yx"===i.axis?"
":"",f=i.autoHideScrollbar?" "+d[6]:"",h="x"!==i.axis&&"rtl"===n.langDir?" "+d[7]:"";i.setWidth&&t.css("width",i.setWidth),i.setHeight&&t.css("height",i.setHeight),i.setLeft="y"!==i.axis&&"rtl"===n.langDir?"989999px":i.setLeft,t.addClass(o+" _"+a+"_"+n.idx+f+h).wrapInner("
");var m=e("#mCSB_"+n.idx),p=e("#mCSB_"+n.idx+"_container");"y"===i.axis||i.advanced.autoExpandHorizontalScroll||p.css("width",x(p)),"outside"===i.scrollbarPosition?("static"===t.css("position")&&t.css("position","relative"),t.css("overflow","visible"),m.addClass("mCSB_outside").after(c)):(m.addClass("mCSB_inside").append(c),p.wrap(u)),w.call(this);var g=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")];g[0].css("min-height",g[0].height()),g[1].css("min-width",g[1].width())},x=function(t){var o=[t[0].scrollWidth,Math.max.apply(Math,t.children().map(function(){return e(this).outerWidth(!0)}).get())],a=t.parent().width();return o[0]>a?o[0]:o[1]>a?o[1]:"100%"},_=function(){var t=e(this),o=t.data(a),n=o.opt,i=e("#mCSB_"+o.idx+"_container");if(n.advanced.autoExpandHorizontalScroll&&"y"!==n.axis){i.css({width:"auto","min-width":0,"overflow-x":"scroll"});var r=Math.ceil(i[0].scrollWidth);3===n.advanced.autoExpandHorizontalScroll||2!==n.advanced.autoExpandHorizontalScroll&&r>i.parent().width()?i.css({width:r,"min-width":"100%","overflow-x":"inherit"}):i.css({"overflow-x":"inherit",position:"absolute"}).wrap("
").css({width:Math.ceil(i[0].getBoundingClientRect().right+.4)-Math.floor(i[0].getBoundingClientRect().left),"min-width":"100%",position:"relative"}).unwrap()}},w=function(){var t=e(this),o=t.data(a),n=o.opt,i=e(".mCSB_"+o.idx+"_scrollbar:first"),r=oe(n.scrollButtons.tabindex)?"tabindex='"+n.scrollButtons.tabindex+"'":"",l=["
","
","
","
"],s=["x"===n.axis?l[2]:l[0],"x"===n.axis?l[3]:l[1],l[2],l[3]];n.scrollButtons.enable&&i.prepend(s[0]).append(s[1]).next(".mCSB_scrollTools").prepend(s[2]).append(s[3])},S=function(){var t=e(this),o=t.data(a),n=e("#mCSB_"+o.idx),i=e("#mCSB_"+o.idx+"_container"),r=[e("#mCSB_"+o.idx+"_dragger_vertical"),e("#mCSB_"+o.idx+"_dragger_horizontal")],l=[n.height()/i.outerHeight(!1),n.width()/i.outerWidth(!1)],c=[parseInt(r[0].css("min-height")),Math.round(l[0]*r[0].parent().height()),parseInt(r[1].css("min-width")),Math.round(l[1]*r[1].parent().width())],d=s&&c[1]
r&&(r=s),c>l&&(l=c),[r>n.height(),l>n.width()]},B=function(){var t=e(this),o=t.data(a),n=o.opt,i=e("#mCSB_"+o.idx),r=e("#mCSB_"+o.idx+"_container"),l=[e("#mCSB_"+o.idx+"_dragger_vertical"),e("#mCSB_"+o.idx+"_dragger_horizontal")];if(Q(t),("x"!==n.axis&&!o.overflowed[0]||"y"===n.axis&&o.overflowed[0])&&(l[0].add(r).css("top",0),G(t,"_resetY")),"y"!==n.axis&&!o.overflowed[1]||"x"===n.axis&&o.overflowed[1]){var s=dx=0;"rtl"===o.langDir&&(s=i.width()-r.outerWidth(!1),dx=Math.abs(s/o.scrollRatio.x)),r.css("left",s),l[1].css("left",dx),G(t,"_resetX")}},T=function(){function t(){r=setTimeout(function(){e.event.special.mousewheel?(clearTimeout(r),W.call(o[0])):t()},100)}var o=e(this),n=o.data(a),i=n.opt;if(!n.bindEvents){if(I.call(this),i.contentTouchScroll&&D.call(this),E.call(this),i.mouseWheel.enable){var r;t()}P.call(this),U.call(this),i.advanced.autoScrollOnFocus&&H.call(this),i.scrollButtons.enable&&F.call(this),i.keyboard.enable&&q.call(this),n.bindEvents=!0}},k=function(){var t=e(this),o=t.data(a),n=o.opt,i=a+"_"+o.idx,r=".mCSB_"+o.idx+"_scrollbar",l=e("#mCSB_"+o.idx+",#mCSB_"+o.idx+"_container,#mCSB_"+o.idx+"_container_wrapper,"+r+" ."+d[12]+",#mCSB_"+o.idx+"_dragger_vertical,#mCSB_"+o.idx+"_dragger_horizontal,"+r+">a"),s=e("#mCSB_"+o.idx+"_container");n.advanced.releaseDraggableSelectors&&l.add(e(n.advanced.releaseDraggableSelectors)),n.advanced.extraDraggableSelectors&&l.add(e(n.advanced.extraDraggableSelectors)),o.bindEvents&&(e(document).add(e(!A()||top.document)).unbind("."+i),l.each(function(){e(this).unbind("."+i)}),clearTimeout(t[0]._focusTimeout),$(t[0],"_focusTimeout"),clearTimeout(o.sequential.step),$(o.sequential,"step"),clearTimeout(s[0].onCompleteTimeout),$(s[0],"onCompleteTimeout"),o.bindEvents=!1)},M=function(t){var o=e(this),n=o.data(a),i=n.opt,r=e("#mCSB_"+n.idx+"_container_wrapper"),l=r.length?r:e("#mCSB_"+n.idx+"_container"),s=[e("#mCSB_"+n.idx+"_scrollbar_vertical"),e("#mCSB_"+n.idx+"_scrollbar_horizontal")],c=[s[0].find(".mCSB_dragger"),s[1].find(".mCSB_dragger")];"x"!==i.axis&&(n.overflowed[0]&&!t?(s[0].add(c[0]).add(s[0].children("a")).css("display","block"),l.removeClass(d[8]+" "+d[10])):(i.alwaysShowScrollbar?(2!==i.alwaysShowScrollbar&&c[0].css("display","none"),l.removeClass(d[10])):(s[0].css("display","none"),l.addClass(d[10])),l.addClass(d[8]))),"y"!==i.axis&&(n.overflowed[1]&&!t?(s[1].add(c[1]).add(s[1].children("a")).css("display","block"),l.removeClass(d[9]+" "+d[11])):(i.alwaysShowScrollbar?(2!==i.alwaysShowScrollbar&&c[1].css("display","none"),l.removeClass(d[11])):(s[1].css("display","none"),l.addClass(d[11])),l.addClass(d[9]))),n.overflowed[0]||n.overflowed[1]?o.removeClass(d[5]):o.addClass(d[5])},O=function(t){var o=t.type,a=t.target.ownerDocument!==document&&null!==frameElement?[e(frameElement).offset().top,e(frameElement).offset().left]:null,n=A()&&t.target.ownerDocument!==top.document&&null!==frameElement?[e(t.view.frameElement).offset().top,e(t.view.frameElement).offset().left]:[0,0];switch(o){case"pointerdown":case"MSPointerDown":case"pointermove":case"MSPointerMove":case"pointerup":case"MSPointerUp":return a?[t.originalEvent.pageY-a[0]+n[0],t.originalEvent.pageX-a[1]+n[1],!1]:[t.originalEvent.pageY,t.originalEvent.pageX,!1];case"touchstart":case"touchmove":case"touchend":var i=t.originalEvent.touches[0]||t.originalEvent.changedTouches[0],r=t.originalEvent.touches.length||t.originalEvent.changedTouches.length;return t.target.ownerDocument!==document?[i.screenY,i.screenX,r>1]:[i.pageY,i.pageX,r>1];default:return a?[t.pageY-a[0]+n[0],t.pageX-a[1]+n[1],!1]:[t.pageY,t.pageX,!1]}},I=function(){function t(e,t,a,n){if(h[0].idleTimer=d.scrollInertia<233?250:0,o.attr("id")===f[1])var i="x",s=(o[0].offsetLeft-t+n)*l.scrollRatio.x;else var i="y",s=(o[0].offsetTop-e+a)*l.scrollRatio.y;G(r,s.toString(),{dir:i,drag:!0})}var o,n,i,r=e(this),l=r.data(a),d=l.opt,u=a+"_"+l.idx,f=["mCSB_"+l.idx+"_dragger_vertical","mCSB_"+l.idx+"_dragger_horizontal"],h=e("#mCSB_"+l.idx+"_container"),m=e("#"+f[0]+",#"+f[1]),p=d.advanced.releaseDraggableSelectors?m.add(e(d.advanced.releaseDraggableSelectors)):m,g=d.advanced.extraDraggableSelectors?e(!A()||top.document).add(e(d.advanced.extraDraggableSelectors)):e(!A()||top.document);m.bind("contextmenu."+u,function(e){e.preventDefault()}).bind("mousedown."+u+" touchstart."+u+" pointerdown."+u+" MSPointerDown."+u,function(t){if(t.stopImmediatePropagation(),t.preventDefault(),ee(t)){c=!0,s&&(document.onselectstart=function(){return!1}),L.call(h,!1),Q(r),o=e(this);var a=o.offset(),l=O(t)[0]-a.top,u=O(t)[1]-a.left,f=o.height()+a.top,m=o.width()+a.left;f>l&&l>0&&m>u&&u>0&&(n=l,i=u),C(o,"active",d.autoExpandScrollbar)}}).bind("touchmove."+u,function(e){e.stopImmediatePropagation(),e.preventDefault();var a=o.offset(),r=O(e)[0]-a.top,l=O(e)[1]-a.left;t(n,i,r,l)}),e(document).add(g).bind("mousemove."+u+" pointermove."+u+" MSPointerMove."+u,function(e){if(o){var a=o.offset(),r=O(e)[0]-a.top,l=O(e)[1]-a.left;if(n===r&&i===l)return;t(n,i,r,l)}}).add(p).bind("mouseup."+u+" touchend."+u+" pointerup."+u+" MSPointerUp."+u,function(){o&&(C(o,"active",d.autoExpandScrollbar),o=null),c=!1,s&&(document.onselectstart=null),L.call(h,!0)})},D=function(){function o(e){if(!te(e)||c||O(e)[2])return void(t=0);t=1,b=0,C=0,d=1,y.removeClass("mCS_touch_action");var o=I.offset();u=O(e)[0]-o.top,f=O(e)[1]-o.left,z=[O(e)[0],O(e)[1]]}function n(e){if(te(e)&&!c&&!O(e)[2]&&(T.documentTouchScroll||e.preventDefault(),e.stopImmediatePropagation(),(!C||b)&&d)){g=K();var t=M.offset(),o=O(e)[0]-t.top,a=O(e)[1]-t.left,n="mcsLinearOut";if(E.push(o),W.push(a),z[2]=Math.abs(O(e)[0]-z[0]),z[3]=Math.abs(O(e)[1]-z[1]),B.overflowed[0])var i=D[0].parent().height()-D[0].height(),r=u-o>0&&o-u>-(i*B.scrollRatio.y)&&(2*z[3]0&&a-f>-(l*B.scrollRatio.x)&&(2*z[2]30)){_=1e3/(v-p);var n="mcsEaseOut",i=2.5>_,r=i?[E[E.length-2],W[W.length-2]]:[0,0];x=i?[o-r[0],a-r[1]]:[o-h,a-m];var u=[Math.abs(x[0]),Math.abs(x[1])];_=i?[Math.abs(x[0]/4),Math.abs(x[1]/4)]:[_,_];var f=[Math.abs(I[0].offsetTop)-x[0]*l(u[0]/_[0],_[0]),Math.abs(I[0].offsetLeft)-x[1]*l(u[1]/_[1],_[1])];w="yx"===T.axis?[f[0],f[1]]:"x"===T.axis?[null,f[1]]:[f[0],null],S=[4*u[0]+T.scrollInertia,4*u[1]+T.scrollInertia];var y=parseInt(T.contentTouchScroll)||0;w[0]=u[0]>y?w[0]:0,w[1]=u[1]>y?w[1]:0,B.overflowed[0]&&s(w[0],S[0],n,"y",L,!1),B.overflowed[1]&&s(w[1],S[1],n,"x",L,!1)}}}function l(e,t){var o=[1.5*t,2*t,t/1.5,t/2];return e>90?t>4?o[0]:o[3]:e>60?t>3?o[3]:o[2]:e>30?t>8?o[1]:t>6?o[0]:t>4?t:o[2]:t>8?t:o[3]}function s(e,t,o,a,n,i){e&&G(y,e.toString(),{dur:t,scrollEasing:o,dir:a,overwrite:n,drag:i})}var d,u,f,h,m,p,g,v,x,_,w,S,b,C,y=e(this),B=y.data(a),T=B.opt,k=a+"_"+B.idx,M=e("#mCSB_"+B.idx),I=e("#mCSB_"+B.idx+"_container"),D=[e("#mCSB_"+B.idx+"_dragger_vertical"),e("#mCSB_"+B.idx+"_dragger_horizontal")],E=[],W=[],R=0,L="yx"===T.axis?"none":"all",z=[],P=I.find("iframe"),H=["touchstart."+k+" pointerdown."+k+" MSPointerDown."+k,"touchmove."+k+" pointermove."+k+" MSPointerMove."+k,"touchend."+k+" pointerup."+k+" MSPointerUp."+k],U=void 0!==document.body.style.touchAction&&""!==document.body.style.touchAction;I.bind(H[0],function(e){o(e)}).bind(H[1],function(e){n(e)}),M.bind(H[0],function(e){i(e)}).bind(H[2],function(e){r(e)}),P.length&&P.each(function(){e(this).bind("load",function(){A(this)&&e(this.contentDocument||this.contentWindow.document).bind(H[0],function(e){o(e),i(e)}).bind(H[1],function(e){n(e)}).bind(H[2],function(e){r(e)})})})},E=function(){function o(){return window.getSelection?window.getSelection().toString():document.selection&&"Control"!=document.selection.type?document.selection.createRange().text:0}function n(e,t,o){d.type=o&&i?"stepped":"stepless",d.scrollAmount=10,j(r,e,t,"mcsLinearOut",o?60:null)}var i,r=e(this),l=r.data(a),s=l.opt,d=l.sequential,u=a+"_"+l.idx,f=e("#mCSB_"+l.idx+"_container"),h=f.parent();f.bind("mousedown."+u,function(){t||i||(i=1,c=!0)}).add(document).bind("mousemove."+u,function(e){if(!t&&i&&o()){var a=f.offset(),r=O(e)[0]-a.top+f[0].offsetTop,c=O(e)[1]-a.left+f[0].offsetLeft;r>0&&r0&&cr?n("on",38):r>h.height()&&n("on",40)),"y"!==s.axis&&l.overflowed[1]&&(0>c?n("on",37):c>h.width()&&n("on",39)))}}).bind("mouseup."+u+" dragend."+u,function(){t||(i&&(i=0,n("off",null)),c=!1)})},W=function(){function t(t,a){if(Q(o),!z(o,t.target)){var r="auto"!==i.mouseWheel.deltaFactor?parseInt(i.mouseWheel.deltaFactor):s&&t.deltaFactor<100?100:t.deltaFactor||100,d=i.scrollInertia;if("x"===i.axis||"x"===i.mouseWheel.axis)var u="x",f=[Math.round(r*n.scrollRatio.x),parseInt(i.mouseWheel.scrollAmount)],h="auto"!==i.mouseWheel.scrollAmount?f[1]:f[0]>=l.width()?.9*l.width():f[0],m=Math.abs(e("#mCSB_"+n.idx+"_container")[0].offsetLeft),p=c[1][0].offsetLeft,g=c[1].parent().width()-c[1].width(),v="y"===i.mouseWheel.axis?t.deltaY||a:t.deltaX;else var u="y",f=[Math.round(r*n.scrollRatio.y),parseInt(i.mouseWheel.scrollAmount)],h="auto"!==i.mouseWheel.scrollAmount?f[1]:f[0]>=l.height()?.9*l.height():f[0],m=Math.abs(e("#mCSB_"+n.idx+"_container")[0].offsetTop),p=c[0][0].offsetTop,g=c[0].parent().height()-c[0].height(),v=t.deltaY||a;"y"===u&&!n.overflowed[0]||"x"===u&&!n.overflowed[1]||((i.mouseWheel.invert||t.webkitDirectionInvertedFromDevice)&&(v=-v),i.mouseWheel.normalizeDelta&&(v=0>v?-1:1),(v>0&&0!==p||0>v&&p!==g||i.mouseWheel.preventDefault)&&(t.stopImmediatePropagation(),t.preventDefault()),t.deltaFactor<5&&!i.mouseWheel.normalizeDelta&&(h=t.deltaFactor,d=17),G(o,(m-v*h).toString(),{dir:u,dur:d}))}}if(e(this).data(a)){var o=e(this),n=o.data(a),i=n.opt,r=a+"_"+n.idx,l=e("#mCSB_"+n.idx),c=[e("#mCSB_"+n.idx+"_dragger_vertical"),e("#mCSB_"+n.idx+"_dragger_horizontal")],d=e("#mCSB_"+n.idx+"_container").find("iframe");d.length&&d.each(function(){e(this).bind("load",function(){A(this)&&e(this.contentDocument||this.contentWindow.document).bind("mousewheel."+r,function(e,o){t(e,o)})})}),l.bind("mousewheel."+r,function(e,o){t(e,o)})}},R=new Object,A=function(t){var o=!1,a=!1,n=null;if(void 0===t?a="#empty":void 0!==e(t).attr("id")&&(a=e(t).attr("id")),a!==!1&&void 0!==R[a])return R[a];if(t){try{var i=t.contentDocument||t.contentWindow.document;n=i.body.innerHTML}catch(r){}o=null!==n}else{try{var i=top.document;n=i.body.innerHTML}catch(r){}o=null!==n}return a!==!1&&(R[a]=o),o},L=function(e){var t=this.find("iframe");if(t.length){var o=e?"auto":"none";t.css("pointer-events",o)}},z=function(t,o){var n=o.nodeName.toLowerCase(),i=t.data(a).opt.mouseWheel.disableOver,r=["select","textarea"];return e.inArray(n,i)>-1&&!(e.inArray(n,r)>-1&&!e(o).is(":focus"))},P=function(){var t,o=e(this),n=o.data(a),i=a+"_"+n.idx,r=e("#mCSB_"+n.idx+"_container"),l=r.parent(),s=e(".mCSB_"+n.idx+"_scrollbar ."+d[12]);s.bind("mousedown."+i+" touchstart."+i+" pointerdown."+i+" MSPointerDown."+i,function(o){c=!0,e(o.target).hasClass("mCSB_dragger")||(t=1)}).bind("touchend."+i+" pointerup."+i+" MSPointerUp."+i,function(){c=!1}).bind("click."+i,function(a){if(t&&(t=0,e(a.target).hasClass(d[12])||e(a.target).hasClass("mCSB_draggerRail"))){Q(o);var i=e(this),s=i.find(".mCSB_dragger");if(i.parent(".mCSB_scrollTools_horizontal").length>0){if(!n.overflowed[1])return;var c="x",u=a.pageX>s.offset().left?-1:1,f=Math.abs(r[0].offsetLeft)-u*(.9*l.width())}else{if(!n.overflowed[0])return;var c="y",u=a.pageY>s.offset().top?-1:1,f=Math.abs(r[0].offsetTop)-u*(.9*l.height())}G(o,f.toString(),{dir:c,scrollEasing:"mcsEaseInOut"})}})},H=function(){var t=e(this),o=t.data(a),n=o.opt,i=a+"_"+o.idx,r=e("#mCSB_"+o.idx+"_container"),l=r.parent();r.bind("focusin."+i,function(){var o=e(document.activeElement),a=r.find(".mCustomScrollBox").length,i=0;o.is(n.advanced.autoScrollOnFocus)&&(Q(t),clearTimeout(t[0]._focusTimeout),t[0]._focusTimer=a?(i+17)*a:0,t[0]._focusTimeout=setTimeout(function(){var e=[ae(o)[0],ae(o)[1]],a=[r[0].offsetTop,r[0].offsetLeft],s=[a[0]+e[0]>=0&&a[0]+e[0]=0&&a[0]+e[1]a");s.bind("contextmenu."+r,function(e){e.preventDefault()}).bind("mousedown."+r+" touchstart."+r+" pointerdown."+r+" MSPointerDown."+r+" mouseup."+r+" touchend."+r+" pointerup."+r+" MSPointerUp."+r+" mouseout."+r+" pointerout."+r+" MSPointerOut."+r+" click."+r,function(a){function r(e,o){i.scrollAmount=n.scrollButtons.scrollAmount,j(t,e,o)}if(a.preventDefault(),ee(a)){var l=e(this).attr("class");switch(i.type=n.scrollButtons.scrollType,a.type){case"mousedown":case"touchstart":case"pointerdown":case"MSPointerDown":if("stepped"===i.type)return;c=!0,o.tweenRunning=!1,r("on",l);break;case"mouseup":case"touchend":case"pointerup":case"MSPointerUp":case"mouseout":case"pointerout":case"MSPointerOut":if("stepped"===i.type)return;c=!1,i.dir&&r("off",l);break;case"click":if("stepped"!==i.type||o.tweenRunning)return;r("on",l)}}})},q=function(){function t(t){function a(e,t){r.type=i.keyboard.scrollType,r.scrollAmount=i.keyboard.scrollAmount,"stepped"===r.type&&n.tweenRunning||j(o,e,t)}switch(t.type){case"blur":n.tweenRunning&&r.dir&&a("off",null);break;case"keydown":case"keyup":var l=t.keyCode?t.keyCode:t.which,s="on";if("x"!==i.axis&&(38===l||40===l)||"y"!==i.axis&&(37===l||39===l)){if((38===l||40===l)&&!n.overflowed[0]||(37===l||39===l)&&!n.overflowed[1])return;"keyup"===t.type&&(s="off"),e(document.activeElement).is(u)||(t.preventDefault(),t.stopImmediatePropagation(),a(s,l))}else if(33===l||34===l){if((n.overflowed[0]||n.overflowed[1])&&(t.preventDefault(),t.stopImmediatePropagation()),"keyup"===t.type){Q(o);var f=34===l?-1:1;if("x"===i.axis||"yx"===i.axis&&n.overflowed[1]&&!n.overflowed[0])var h="x",m=Math.abs(c[0].offsetLeft)-f*(.9*d.width());else var h="y",m=Math.abs(c[0].offsetTop)-f*(.9*d.height());G(o,m.toString(),{dir:h,scrollEasing:"mcsEaseInOut"})}}else if((35===l||36===l)&&!e(document.activeElement).is(u)&&((n.overflowed[0]||n.overflowed[1])&&(t.preventDefault(),t.stopImmediatePropagation()),"keyup"===t.type)){if("x"===i.axis||"yx"===i.axis&&n.overflowed[1]&&!n.overflowed[0])var h="x",m=35===l?Math.abs(d.width()-c.outerWidth(!1)):0;else var h="y",m=35===l?Math.abs(d.height()-c.outerHeight(!1)):0;G(o,m.toString(),{dir:h,scrollEasing:"mcsEaseInOut"})}}}var o=e(this),n=o.data(a),i=n.opt,r=n.sequential,l=a+"_"+n.idx,s=e("#mCSB_"+n.idx),c=e("#mCSB_"+n.idx+"_container"),d=c.parent(),u="input,textarea,select,datalist,keygen,[contenteditable='true']",f=c.find("iframe"),h=["blur."+l+" keydown."+l+" keyup."+l];f.length&&f.each(function(){e(this).bind("load",function(){A(this)&&e(this.contentDocument||this.contentWindow.document).bind(h[0],function(e){t(e)})})}),s.attr("tabindex","0").bind(h[0],function(e){t(e)})},j=function(t,o,n,i,r){function l(e){u.snapAmount&&(f.scrollAmount=u.snapAmount instanceof Array?"x"===f.dir[0]?u.snapAmount[1]:u.snapAmount[0]:u.snapAmount);var o="stepped"!==f.type,a=r?r:e?o?p/1.5:g:1e3/60,n=e?o?7.5:40:2.5,s=[Math.abs(h[0].offsetTop),Math.abs(h[0].offsetLeft)],d=[c.scrollRatio.y>10?10:c.scrollRatio.y,c.scrollRatio.x>10?10:c.scrollRatio.x],m="x"===f.dir[0]?s[1]+f.dir[1]*(d[1]*n):s[0]+f.dir[1]*(d[0]*n),v="x"===f.dir[0]?s[1]+f.dir[1]*parseInt(f.scrollAmount):s[0]+f.dir[1]*parseInt(f.scrollAmount),x="auto"!==f.scrollAmount?v:m,_=i?i:e?o?"mcsLinearOut":"mcsEaseInOut":"mcsLinear",w=!!e;return e&&17>a&&(x="x"===f.dir[0]?s[1]:s[0]),G(t,x.toString(),{dir:f.dir[0],scrollEasing:_,dur:a,onComplete:w}),e?void(f.dir=!1):(clearTimeout(f.step),void(f.step=setTimeout(function(){l()},a)))}function s(){clearTimeout(f.step),$(f,"step"),Q(t)}var c=t.data(a),u=c.opt,f=c.sequential,h=e("#mCSB_"+c.idx+"_container"),m="stepped"===f.type,p=u.scrollInertia<26?26:u.scrollInertia,g=u.scrollInertia<1?17:u.scrollInertia;switch(o){case"on":if(f.dir=[n===d[16]||n===d[15]||39===n||37===n?"x":"y",n===d[13]||n===d[15]||38===n||37===n?-1:1],Q(t),oe(n)&&"stepped"===f.type)return;l(m);break;case"off":s(),(m||c.tweenRunning&&f.dir)&&l(!0)}},Y=function(t){var o=e(this).data(a).opt,n=[];return"function"==typeof t&&(t=t()),t instanceof Array?n=t.length>1?[t[0],t[1]]:"x"===o.axis?[null,t[0]]:[t[0],null]:(n[0]=t.y?t.y:t.x||"x"===o.axis?null:t,n[1]=t.x?t.x:t.y||"y"===o.axis?null:t),"function"==typeof n[0]&&(n[0]=n[0]()),"function"==typeof n[1]&&(n[1]=n[1]()),n},X=function(t,o){if(null!=t&&"undefined"!=typeof t){var n=e(this),i=n.data(a),r=i.opt,l=e("#mCSB_"+i.idx+"_container"),s=l.parent(),c=typeof t;o||(o="x"===r.axis?"x":"y");var d="x"===o?l.outerWidth(!1)-s.width():l.outerHeight(!1)-s.height(),f="x"===o?l[0].offsetLeft:l[0].offsetTop,h="x"===o?"left":"top";switch(c){case"function":return t();case"object":var m=t.jquery?t:e(t);if(!m.length)return;return"x"===o?ae(m)[1]:ae(m)[0];case"string":case"number":if(oe(t))return Math.abs(t);if(-1!==t.indexOf("%"))return Math.abs(d*parseInt(t)/100);if(-1!==t.indexOf("-="))return Math.abs(f-parseInt(t.split("-=")[1]));if(-1!==t.indexOf("+=")){var p=f+parseInt(t.split("+=")[1]);return p>=0?0:Math.abs(p)}if(-1!==t.indexOf("px")&&oe(t.split("px")[0]))return Math.abs(t.split("px")[0]);if("top"===t||"left"===t)return 0;if("bottom"===t)return Math.abs(s.height()-l.outerHeight(!1));if("right"===t)return Math.abs(s.width()-l.outerWidth(!1));if("first"===t||"last"===t){var m=l.find(":"+t);return"x"===o?ae(m)[1]:ae(m)[0]}return e(t).length?"x"===o?ae(e(t))[1]:ae(e(t))[0]:(l.css(h,t),void u.update.call(null,n[0]))}}},N=function(t){function o(){return clearTimeout(f[0].autoUpdate),0===l.parents("html").length?void(l=null):void(f[0].autoUpdate=setTimeout(function(){return c.advanced.updateOnSelectorChange&&(s.poll.change.n=i(),s.poll.change.n!==s.poll.change.o)?(s.poll.change.o=s.poll.change.n,void r(3)):c.advanced.updateOnContentResize&&(s.poll.size.n=l[0].scrollHeight+l[0].scrollWidth+f[0].offsetHeight+l[0].offsetHeight+l[0].offsetWidth,s.poll.size.n!==s.poll.size.o)?(s.poll.size.o=s.poll.size.n,void r(1)):!c.advanced.updateOnImageLoad||"auto"===c.advanced.updateOnImageLoad&&"y"===c.axis||(s.poll.img.n=f.find("img").length,s.poll.img.n===s.poll.img.o)?void((c.advanced.updateOnSelectorChange||c.advanced.updateOnContentResize||c.advanced.updateOnImageLoad)&&o()):(s.poll.img.o=s.poll.img.n,void f.find("img").each(function(){n(this)}))},c.advanced.autoUpdateTimeout))}function n(t){function o(e,t){return function(){
+return t.apply(e,arguments)}}function a(){this.onload=null,e(t).addClass(d[2]),r(2)}if(e(t).hasClass(d[2]))return void r();var n=new Image;n.onload=o(n,a),n.src=t.src}function i(){c.advanced.updateOnSelectorChange===!0&&(c.advanced.updateOnSelectorChange="*");var e=0,t=f.find(c.advanced.updateOnSelectorChange);return c.advanced.updateOnSelectorChange&&t.length>0&&t.each(function(){e+=this.offsetHeight+this.offsetWidth}),e}function r(e){clearTimeout(f[0].autoUpdate),u.update.call(null,l[0],e)}var l=e(this),s=l.data(a),c=s.opt,f=e("#mCSB_"+s.idx+"_container");return t?(clearTimeout(f[0].autoUpdate),void $(f[0],"autoUpdate")):void o()},V=function(e,t,o){return Math.round(e/t)*t-o},Q=function(t){var o=t.data(a),n=e("#mCSB_"+o.idx+"_container,#mCSB_"+o.idx+"_container_wrapper,#mCSB_"+o.idx+"_dragger_vertical,#mCSB_"+o.idx+"_dragger_horizontal");n.each(function(){Z.call(this)})},G=function(t,o,n){function i(e){return s&&c.callbacks[e]&&"function"==typeof c.callbacks[e]}function r(){return[c.callbacks.alwaysTriggerOffsets||w>=S[0]+y,c.callbacks.alwaysTriggerOffsets||-B>=w]}function l(){var e=[h[0].offsetTop,h[0].offsetLeft],o=[x[0].offsetTop,x[0].offsetLeft],a=[h.outerHeight(!1),h.outerWidth(!1)],i=[f.height(),f.width()];t[0].mcs={content:h,top:e[0],left:e[1],draggerTop:o[0],draggerLeft:o[1],topPct:Math.round(100*Math.abs(e[0])/(Math.abs(a[0])-i[0])),leftPct:Math.round(100*Math.abs(e[1])/(Math.abs(a[1])-i[1])),direction:n.dir}}var s=t.data(a),c=s.opt,d={trigger:"internal",dir:"y",scrollEasing:"mcsEaseOut",drag:!1,dur:c.scrollInertia,overwrite:"all",callbacks:!0,onStart:!0,onUpdate:!0,onComplete:!0},n=e.extend(d,n),u=[n.dur,n.drag?0:n.dur],f=e("#mCSB_"+s.idx),h=e("#mCSB_"+s.idx+"_container"),m=h.parent(),p=c.callbacks.onTotalScrollOffset?Y.call(t,c.callbacks.onTotalScrollOffset):[0,0],g=c.callbacks.onTotalScrollBackOffset?Y.call(t,c.callbacks.onTotalScrollBackOffset):[0,0];if(s.trigger=n.trigger,0===m.scrollTop()&&0===m.scrollLeft()||(e(".mCSB_"+s.idx+"_scrollbar").css("visibility","visible"),m.scrollTop(0).scrollLeft(0)),"_resetY"!==o||s.contentReset.y||(i("onOverflowYNone")&&c.callbacks.onOverflowYNone.call(t[0]),s.contentReset.y=1),"_resetX"!==o||s.contentReset.x||(i("onOverflowXNone")&&c.callbacks.onOverflowXNone.call(t[0]),s.contentReset.x=1),"_resetY"!==o&&"_resetX"!==o){if(!s.contentReset.y&&t[0].mcs||!s.overflowed[0]||(i("onOverflowY")&&c.callbacks.onOverflowY.call(t[0]),s.contentReset.x=null),!s.contentReset.x&&t[0].mcs||!s.overflowed[1]||(i("onOverflowX")&&c.callbacks.onOverflowX.call(t[0]),s.contentReset.x=null),c.snapAmount){var v=c.snapAmount instanceof Array?"x"===n.dir?c.snapAmount[1]:c.snapAmount[0]:c.snapAmount;o=V(o,v,c.snapOffset)}switch(n.dir){case"x":var x=e("#mCSB_"+s.idx+"_dragger_horizontal"),_="left",w=h[0].offsetLeft,S=[f.width()-h.outerWidth(!1),x.parent().width()-x.width()],b=[o,0===o?0:o/s.scrollRatio.x],y=p[1],B=g[1],T=y>0?y/s.scrollRatio.x:0,k=B>0?B/s.scrollRatio.x:0;break;case"y":var x=e("#mCSB_"+s.idx+"_dragger_vertical"),_="top",w=h[0].offsetTop,S=[f.height()-h.outerHeight(!1),x.parent().height()-x.height()],b=[o,0===o?0:o/s.scrollRatio.y],y=p[0],B=g[0],T=y>0?y/s.scrollRatio.y:0,k=B>0?B/s.scrollRatio.y:0}b[1]<0||0===b[0]&&0===b[1]?b=[0,0]:b[1]>=S[1]?b=[S[0],S[1]]:b[0]=-b[0],t[0].mcs||(l(),i("onInit")&&c.callbacks.onInit.call(t[0])),clearTimeout(h[0].onCompleteTimeout),J(x[0],_,Math.round(b[1]),u[1],n.scrollEasing),!s.tweenRunning&&(0===w&&b[0]>=0||w===S[0]&&b[0]<=S[0])||J(h[0],_,Math.round(b[0]),u[0],n.scrollEasing,n.overwrite,{onStart:function(){n.callbacks&&n.onStart&&!s.tweenRunning&&(i("onScrollStart")&&(l(),c.callbacks.onScrollStart.call(t[0])),s.tweenRunning=!0,C(x),s.cbOffsets=r())},onUpdate:function(){n.callbacks&&n.onUpdate&&i("whileScrolling")&&(l(),c.callbacks.whileScrolling.call(t[0]))},onComplete:function(){if(n.callbacks&&n.onComplete){"yx"===c.axis&&clearTimeout(h[0].onCompleteTimeout);var e=h[0].idleTimer||0;h[0].onCompleteTimeout=setTimeout(function(){i("onScroll")&&(l(),c.callbacks.onScroll.call(t[0])),i("onTotalScroll")&&b[1]>=S[1]-T&&s.cbOffsets[0]&&(l(),c.callbacks.onTotalScroll.call(t[0])),i("onTotalScrollBack")&&b[1]<=k&&s.cbOffsets[1]&&(l(),c.callbacks.onTotalScrollBack.call(t[0])),s.tweenRunning=!1,h[0].idleTimer=0,C(x,"hide")},e)}}})}},J=function(e,t,o,a,n,i,r){function l(){S.stop||(x||m.call(),x=K()-v,s(),x>=S.time&&(S.time=x>S.time?x+f-(x-S.time):x+f-1,S.time0?(S.currVal=u(S.time,_,b,a,n),w[t]=Math.round(S.currVal)+"px"):w[t]=o+"px",p.call()}function c(){f=1e3/60,S.time=x+f,h=window.requestAnimationFrame?window.requestAnimationFrame:function(e){return s(),setTimeout(e,.01)},S.id=h(l)}function d(){null!=S.id&&(window.requestAnimationFrame?window.cancelAnimationFrame(S.id):clearTimeout(S.id),S.id=null)}function u(e,t,o,a,n){switch(n){case"linear":case"mcsLinear":return o*e/a+t;case"mcsLinearOut":return e/=a,e--,o*Math.sqrt(1-e*e)+t;case"easeInOutSmooth":return e/=a/2,1>e?o/2*e*e+t:(e--,-o/2*(e*(e-2)-1)+t);case"easeInOutStrong":return e/=a/2,1>e?o/2*Math.pow(2,10*(e-1))+t:(e--,o/2*(-Math.pow(2,-10*e)+2)+t);case"easeInOut":case"mcsEaseInOut":return e/=a/2,1>e?o/2*e*e*e+t:(e-=2,o/2*(e*e*e+2)+t);case"easeOutSmooth":return e/=a,e--,-o*(e*e*e*e-1)+t;case"easeOutStrong":return o*(-Math.pow(2,-10*e/a)+1)+t;case"easeOut":case"mcsEaseOut":default:var i=(e/=a)*e,r=i*e;return t+o*(.499999999999997*r*i+-2.5*i*i+5.5*r+-6.5*i+4*e)}}e._mTween||(e._mTween={top:{},left:{}});var f,h,r=r||{},m=r.onStart||function(){},p=r.onUpdate||function(){},g=r.onComplete||function(){},v=K(),x=0,_=e.offsetTop,w=e.style,S=e._mTween[t];"left"===t&&(_=e.offsetLeft);var b=o-_;S.stop=0,"none"!==i&&d(),c()},K=function(){return window.performance&&window.performance.now?window.performance.now():window.performance&&window.performance.webkitNow?window.performance.webkitNow():Date.now?Date.now():(new Date).getTime()},Z=function(){var e=this;e._mTween||(e._mTween={top:{},left:{}});for(var t=["top","left"],o=0;o=0&&a[0]+ae(n)[0]=0&&a[1]+ae(n)[1]=0&&r[1]-i[1]*l[1][0]<0&&r[1]+n[1]-i[1]*l[1][1]>=0},mcsOverflow:e.expr[":"].mcsOverflow||function(t){var o=e(t).data(a);if(o)return o.overflowed[0]||o.overflowed[1]}})})})});
diff --git a/public/assets/homepage/js/vendors/jquery.mcustomscrollbar.concat.min.js:Zone.Identifier b/public/assets/homepage/js/vendors/jquery.mcustomscrollbar.concat.min.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/jquery.mcustomscrollbar.concat.min.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/justified-gallery.js b/public/assets/homepage/js/vendors/justified-gallery.js
new file mode 100644
index 0000000..97baf75
--- /dev/null
+++ b/public/assets/homepage/js/vendors/justified-gallery.js
@@ -0,0 +1,1246 @@
+/*!
+ Justified Gallery
+ Version: 3.8.1
+ Plugin URL: http://miromannino.github.io/Justified-Gallery/
+ License: Copyright (c) 2020 Miro Mannino | Released under the MIT License
+!*/
+
+(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // Node/CommonJS
+ module.exports = function (root, jQuery) {
+ if (jQuery === undefined) {
+ // require('jQuery') returns a factory that requires window to
+ // build a jQuery instance, we normalize how we use modules
+ // that require this pattern but the window provided is a noop
+ // if it's defined (how jquery works)
+ if (typeof window !== 'undefined') {
+ jQuery = require('jquery');
+ }
+ else {
+ jQuery = require('jquery')(root);
+ }
+ }
+ factory(jQuery);
+ return jQuery;
+ };
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+
+ /**
+ * Justified Gallery controller constructor
+ *
+ * @param $gallery the gallery to build
+ * @param settings the settings (the defaults are in JustifiedGallery.defaults)
+ * @constructor
+ */
+ var JustifiedGallery = function ($gallery, settings) {
+
+ this.settings = settings;
+ this.checkSettings();
+
+ this.imgAnalyzerTimeout = null;
+ this.entries = null;
+ this.buildingRow = {
+ entriesBuff: [],
+ width: 0,
+ height: 0,
+ aspectRatio: 0
+ };
+ this.lastFetchedEntry = null;
+ this.lastAnalyzedIndex = -1;
+ this.yield = {
+ every: 2, // do a flush every n flushes (must be greater than 1)
+ flushed: 0 // flushed rows without a yield
+ };
+ this.border = settings.border >= 0 ? settings.border : settings.margins;
+ this.maxRowHeight = this.retrieveMaxRowHeight();
+ this.suffixRanges = this.retrieveSuffixRanges();
+ this.offY = this.border;
+ this.rows = 0;
+ this.spinner = {
+ phase: 0,
+ timeSlot: 150,
+ $el: $('
'),
+ intervalId: null
+ };
+ this.scrollBarOn = false;
+ this.checkWidthIntervalId = null;
+ this.galleryWidth = $gallery.width();
+ this.$gallery = $gallery;
+
+ };
+
+ /** @returns {String} the best suffix given the width and the height */
+ JustifiedGallery.prototype.getSuffix = function (width, height) {
+ var longestSide, i;
+ longestSide = (width > height) ? width : height;
+ for (i = 0; i < this.suffixRanges.length; i++) {
+ if (longestSide <= this.suffixRanges[i]) {
+ return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
+ }
+ }
+ return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
+ };
+
+ /**
+ * Remove the suffix from the string
+ *
+ * @returns {string} a new string without the suffix
+ */
+ JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
+ return str.substring(0, str.length - suffix.length);
+ };
+
+ /**
+ * @returns {boolean} a boolean to say if the suffix is contained in the str or not
+ */
+ JustifiedGallery.prototype.endsWith = function (str, suffix) {
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+ };
+
+ /**
+ * Get the used suffix of a particular url
+ *
+ * @param str
+ * @returns {String} return the used suffix
+ */
+ JustifiedGallery.prototype.getUsedSuffix = function (str) {
+ for (var si in this.settings.sizeRangeSuffixes) {
+ if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
+ if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
+ if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
+ }
+ }
+ return '';
+ };
+
+ /**
+ * Given an image src, with the width and the height, returns the new image src with the
+ * best suffix to show the best quality thumbnail.
+ *
+ * @returns {String} the suffix to use
+ */
+ JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
+ var newImageSrc;
+
+ if (this.settings.thumbnailPath) {
+ newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
+ } else {
+ var matchRes = imageSrc.match(this.settings.extension);
+ var ext = (matchRes !== null) ? matchRes[0] : '';
+ newImageSrc = imageSrc.replace(this.settings.extension, '');
+ newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
+ newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
+ }
+
+ return newImageSrc;
+ };
+
+ /**
+ * Shows the images that is in the given entry
+ *
+ * @param $entry the entry
+ * @param callback the callback that is called when the show animation is finished
+ */
+ JustifiedGallery.prototype.showImg = function ($entry, callback) {
+ if (this.settings.cssAnimation) {
+ $entry.addClass('jg-entry-visible');
+ if (callback) callback();
+ } else {
+ $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
+ $entry.find(this.settings.imgSelector).stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
+ }
+ };
+
+ /**
+ * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
+ * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
+ *
+ * @param $image the image to analyze
+ * @returns {String} the extracted src
+ */
+ JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
+ var imageSrc = $image.data('safe-src');
+ var imageSrcLoc = 'data-safe-src';
+ if (typeof imageSrc === 'undefined') {
+ imageSrc = $image.attr('src');
+ imageSrcLoc = 'src';
+ }
+ $image.data('jg.originalSrc', imageSrc); // this is saved for the destroy method
+ $image.data('jg.src', imageSrc); // this will change overtime
+ $image.data('jg.originalSrcLoc', imageSrcLoc); // this is saved for the destroy method
+ return imageSrc;
+ };
+
+ /** @returns {jQuery} the image in the given entry */
+ JustifiedGallery.prototype.imgFromEntry = function ($entry) {
+ var $img = $entry.find(this.settings.imgSelector);
+ return $img.length === 0 ? null : $img;
+ };
+
+ /** @returns {jQuery} the caption in the given entry */
+ JustifiedGallery.prototype.captionFromEntry = function ($entry) {
+ var $caption = $entry.find('> .jg-caption');
+ return $caption.length === 0 ? null : $caption;
+ };
+
+ /**
+ * Display the entry
+ *
+ * @param {jQuery} $entry the entry to display
+ * @param {int} x the x position where the entry must be positioned
+ * @param y the y position where the entry must be positioned
+ * @param imgWidth the image width
+ * @param imgHeight the image height
+ * @param rowHeight the row height of the row that owns the entry
+ */
+ JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
+ $entry.width(imgWidth);
+ $entry.height(rowHeight);
+ $entry.css('top', y);
+ $entry.css('left', x);
+
+ var $image = this.imgFromEntry($entry);
+ if ($image !== null) {
+ $image.css('width', imgWidth);
+ $image.css('height', imgHeight);
+ $image.css('margin-left', - imgWidth / 2);
+ $image.css('margin-top', - imgHeight / 2);
+
+ // Image reloading for an high quality of thumbnails
+ var imageSrc = $image.data('jg.src');
+ if (imageSrc) {
+ imageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
+
+ $image.one('error', function () {
+ this.resetImgSrc($image); //revert to the original thumbnail
+ });
+
+ var loadNewImage = function () {
+ // if (imageSrc !== newImageSrc) {
+ $image.attr('src', imageSrc);
+ // }
+ };
+
+ if ($entry.data('jg.loaded') === 'skipped' && imageSrc) {
+ this.onImageEvent(imageSrc, (function() {
+ this.showImg($entry, loadNewImage); //load the new image after the fadeIn
+ $entry.data('jg.loaded', true);
+ }).bind(this));
+ } else {
+ this.showImg($entry, loadNewImage); //load the new image after the fadeIn
+ }
+
+ }
+
+ } else {
+ this.showImg($entry);
+ }
+
+ this.displayEntryCaption($entry);
+ };
+
+ /**
+ * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
+ * or the 'title' attributes.
+ *
+ * @param {jQuery} $entry the entry to process
+ */
+ JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
+ var $image = this.imgFromEntry($entry);
+ if ($image !== null && this.settings.captions) {
+ var $imgCaption = this.captionFromEntry($entry);
+
+ // Create it if it doesn't exists
+ if ($imgCaption === null) {
+ var caption = $image.attr('alt');
+ if (!this.isValidCaption(caption)) caption = $entry.attr('title');
+ if (this.isValidCaption(caption)) { // Create only we found something
+ $imgCaption = $('' + caption + '
');
+ $entry.append($imgCaption);
+ $entry.data('jg.createdCaption', true);
+ }
+ }
+
+ // Create events (we check again the $imgCaption because it can be still inexistent)
+ if ($imgCaption !== null) {
+ if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
+ this.addCaptionEventsHandlers($entry);
+ }
+ } else {
+ this.removeCaptionEventsHandlers($entry);
+ }
+ };
+
+ /**
+ * Validates the caption
+ *
+ * @param caption The caption that should be validated
+ * @return {boolean} Validation result
+ */
+ JustifiedGallery.prototype.isValidCaption = function (caption) {
+ return (typeof caption !== 'undefined' && caption.length > 0);
+ };
+
+ /**
+ * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
+ * It shows the caption using jQuery (or using CSS if it is configured so)
+ *
+ * @param {Event} eventObject the event object
+ */
+ JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
+ var $caption = this.captionFromEntry($(eventObject.currentTarget));
+ if (this.settings.cssAnimation) {
+ $caption.addClass('jg-caption-visible').removeClass('jg-caption-hidden');
+ } else {
+ $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
+ this.settings.captionSettings.visibleOpacity);
+ }
+ };
+
+ /**
+ * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
+ * It hides the caption using jQuery (or using CSS if it is configured so)
+ *
+ * @param {Event} eventObject the event object
+ */
+ JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
+ var $caption = this.captionFromEntry($(eventObject.currentTarget));
+ if (this.settings.cssAnimation) {
+ $caption.removeClass('jg-caption-visible').removeClass('jg-caption-hidden');
+ } else {
+ $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
+ this.settings.captionSettings.nonVisibleOpacity);
+ }
+ };
+
+ /**
+ * Add the handlers of the entry for the caption
+ *
+ * @param $entry the entry to modify
+ */
+ JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
+ var captionMouseEvents = $entry.data('jg.captionMouseEvents');
+ if (typeof captionMouseEvents === 'undefined') {
+ captionMouseEvents = {
+ mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
+ mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
+ };
+ $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
+ $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
+ $entry.data('jg.captionMouseEvents', captionMouseEvents);
+ }
+ };
+
+ /**
+ * Remove the handlers of the entry for the caption
+ *
+ * @param $entry the entry to modify
+ */
+ JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
+ var captionMouseEvents = $entry.data('jg.captionMouseEvents');
+ if (typeof captionMouseEvents !== 'undefined') {
+ $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
+ $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
+ $entry.removeData('jg.captionMouseEvents');
+ }
+ };
+
+ /**
+ * Clear the building row data to be used for a new row
+ */
+ JustifiedGallery.prototype.clearBuildingRow = function () {
+ this.buildingRow.entriesBuff = [];
+ this.buildingRow.aspectRatio = 0;
+ this.buildingRow.width = 0;
+ };
+
+ /**
+ * Justify the building row, preparing it to
+ *
+ * @param isLastRow
+ * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
+ * @returns a boolean to know if the row has been justified or not
+ */
+ JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow, hiddenRow) {
+ var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
+ var minHeight = 0;
+ var availableWidth = this.galleryWidth - 2 * this.border - (
+ (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
+ var rowHeight = availableWidth / this.buildingRow.aspectRatio;
+ var defaultRowHeight = this.settings.rowHeight;
+ var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
+
+ //Skip the last row if we can't justify it and the lastRow == 'hide'
+ if (hiddenRow || (isLastRow && this.settings.lastRow === 'hide' && !justifiable)) {
+ for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
+ $entry = this.buildingRow.entriesBuff[i];
+ if (this.settings.cssAnimation)
+ $entry.removeClass('jg-entry-visible');
+ else {
+ $entry.stop().fadeTo(0, 0.1);
+ $entry.find('> img, > a > img').fadeTo(0, 0);
+ }
+ }
+ return -1;
+ }
+
+ // With lastRow = nojustify, justify if is justificable (the images will not become too big)
+ if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
+ justify = false;
+
+ if (this.rows > 0) {
+ defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
+ justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
+ }
+ }
+
+ for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
+ $entry = this.buildingRow.entriesBuff[i];
+ imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
+
+ if (justify) {
+ newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
+ newImgH = rowHeight;
+ } else {
+ newImgW = defaultRowHeight * imgAspectRatio;
+ newImgH = defaultRowHeight;
+ }
+
+ availableWidth -= Math.round(newImgW);
+ $entry.data('jg.jwidth', Math.round(newImgW));
+ $entry.data('jg.jheight', Math.ceil(newImgH));
+ if (i === 0 || minHeight > newImgH) minHeight = newImgH;
+ }
+
+ this.buildingRow.height = minHeight;
+ return justify;
+ };
+
+ /**
+ * Flush a row: justify it, modify the gallery height accordingly to the row height
+ *
+ * @param isLastRow
+ * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
+ */
+ JustifiedGallery.prototype.flushRow = function (isLastRow, hiddenRow) {
+ var settings = this.settings;
+ var $entry, buildingRowRes, offX = this.border, i;
+
+ buildingRowRes = this.prepareBuildingRow(isLastRow, hiddenRow);
+ if (hiddenRow || (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1)) {
+ this.clearBuildingRow();
+ return;
+ }
+
+ if (this.maxRowHeight) {
+ if (this.maxRowHeight < this.buildingRow.height) this.buildingRow.height = this.maxRowHeight;
+ }
+
+ //Align last (unjustified) row
+ if (isLastRow && (settings.lastRow === 'center' || settings.lastRow === 'right')) {
+ var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
+
+ for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
+ $entry = this.buildingRow.entriesBuff[i];
+ availableWidth -= $entry.data('jg.jwidth');
+ }
+
+ if (settings.lastRow === 'center')
+ offX += Math.round(availableWidth / 2);
+ else if (settings.lastRow === 'right')
+ offX += availableWidth;
+ }
+
+ var lastEntryIdx = this.buildingRow.entriesBuff.length - 1;
+ for (i = 0; i <= lastEntryIdx; i++) {
+ $entry = this.buildingRow.entriesBuff[this.settings.rtl ? lastEntryIdx - i : i];
+ this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
+ offX += $entry.data('jg.jwidth') + settings.margins;
+ }
+
+ //Gallery Height
+ this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
+ this.setGalleryTempHeight(this.galleryHeightToSet + this.getSpinnerHeight());
+
+ if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
+ //Ready for a new row
+ this.offY += this.buildingRow.height + settings.margins;
+ this.rows += 1;
+ this.clearBuildingRow();
+ this.settings.triggerEvent.call(this, 'jg.rowflush');
+ }
+ };
+
+
+ // Scroll position not restoring: https://github.com/miromannino/Justified-Gallery/issues/221
+ var galleryPrevStaticHeight = 0;
+
+ JustifiedGallery.prototype.rememberGalleryHeight = function () {
+ galleryPrevStaticHeight = this.$gallery.height();
+ this.$gallery.height(galleryPrevStaticHeight);
+ };
+
+ // grow only
+ JustifiedGallery.prototype.setGalleryTempHeight = function (height) {
+ galleryPrevStaticHeight = Math.max(height, galleryPrevStaticHeight);
+ this.$gallery.height(galleryPrevStaticHeight);
+ };
+
+ JustifiedGallery.prototype.setGalleryFinalHeight = function (height) {
+ galleryPrevStaticHeight = height;
+ this.$gallery.height(height);
+ };
+
+ /**
+ * Checks the width of the gallery container, to know if a new justification is needed
+ */
+ JustifiedGallery.prototype.checkWidth = function () {
+ this.checkWidthIntervalId = setInterval($.proxy(function () {
+
+ // if the gallery is not currently visible, abort.
+ if (!this.$gallery.is(":visible")) return;
+
+ var galleryWidth = parseFloat(this.$gallery.width());
+ if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
+ this.galleryWidth = galleryWidth;
+ this.rewind();
+
+ this.rememberGalleryHeight();
+
+ // Restart to analyze
+ this.startImgAnalyzer(true);
+ }
+ }, this), this.settings.refreshTime);
+ };
+
+ /**
+ * @returns {boolean} a boolean saying if the spinner is active or not
+ */
+ JustifiedGallery.prototype.isSpinnerActive = function () {
+ return this.spinner.intervalId !== null;
+ };
+
+ /**
+ * @returns {int} the spinner height
+ */
+ JustifiedGallery.prototype.getSpinnerHeight = function () {
+ return this.spinner.$el.innerHeight();
+ };
+
+ /**
+ * Stops the spinner animation and modify the gallery height to exclude the spinner
+ */
+ JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
+ clearInterval(this.spinner.intervalId);
+ this.spinner.intervalId = null;
+ this.setGalleryTempHeight(this.$gallery.height() - this.getSpinnerHeight());
+ this.spinner.$el.detach();
+ };
+
+ /**
+ * Starts the spinner animation
+ */
+ JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
+ var spinnerContext = this.spinner;
+ var $spinnerPoints = spinnerContext.$el.find('span');
+ clearInterval(spinnerContext.intervalId);
+ this.$gallery.append(spinnerContext.$el);
+ this.setGalleryTempHeight(this.offY + this.buildingRow.height + this.getSpinnerHeight());
+ spinnerContext.intervalId = setInterval(function () {
+ if (spinnerContext.phase < $spinnerPoints.length) {
+ $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
+ } else {
+ $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
+ }
+ spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
+ }, spinnerContext.timeSlot);
+ };
+
+ /**
+ * Rewind the image analysis to start from the first entry.
+ */
+ JustifiedGallery.prototype.rewind = function () {
+ this.lastFetchedEntry = null;
+ this.lastAnalyzedIndex = -1;
+ this.offY = this.border;
+ this.rows = 0;
+ this.clearBuildingRow();
+ };
+
+ /**
+ * @returns {String} `settings.selector` rejecting spinner element
+ */
+ JustifiedGallery.prototype.getSelectorWithoutSpinner = function () {
+ return this.settings.selector + ', div:not(.jg-spinner)';
+ };
+
+ /**
+ * @returns {Array} all entries matched by `settings.selector`
+ */
+ JustifiedGallery.prototype.getAllEntries = function () {
+ var selector = this.getSelectorWithoutSpinner();
+ return this.$gallery.children(selector).toArray();
+ };
+
+ /**
+ * Update the entries searching it from the justified gallery HTML element
+ *
+ * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
+ * @returns {boolean} true if some entries has been founded
+ */
+ JustifiedGallery.prototype.updateEntries = function (norewind) {
+ var newEntries;
+
+ if (norewind && this.lastFetchedEntry != null) {
+ var selector = this.getSelectorWithoutSpinner();
+ newEntries = $(this.lastFetchedEntry).nextAll(selector).toArray();
+ } else {
+ this.entries = [];
+ newEntries = this.getAllEntries();
+ }
+
+ if (newEntries.length > 0) {
+
+ // Sort or randomize
+ if ($.isFunction(this.settings.sort)) {
+ newEntries = this.sortArray(newEntries);
+ } else if (this.settings.randomize) {
+ newEntries = this.shuffleArray(newEntries);
+ }
+ this.lastFetchedEntry = newEntries[newEntries.length - 1];
+
+ // Filter
+ if (this.settings.filter) {
+ newEntries = this.filterArray(newEntries);
+ } else {
+ this.resetFilters(newEntries);
+ }
+
+ }
+
+ this.entries = this.entries.concat(newEntries);
+ return true;
+ };
+
+ /**
+ * Apply the entries order to the DOM, iterating the entries and appending the images
+ *
+ * @param entries the entries that has been modified and that must be re-ordered in the DOM
+ */
+ JustifiedGallery.prototype.insertToGallery = function (entries) {
+ var that = this;
+ $.each(entries, function () {
+ $(this).appendTo(that.$gallery);
+ });
+ };
+
+ /**
+ * Shuffle the array using the Fisher-Yates shuffle algorithm
+ *
+ * @param a the array to shuffle
+ * @return the shuffled array
+ */
+ JustifiedGallery.prototype.shuffleArray = function (a) {
+ var i, j, temp;
+ for (i = a.length - 1; i > 0; i--) {
+ j = Math.floor(Math.random() * (i + 1));
+ temp = a[i];
+ a[i] = a[j];
+ a[j] = temp;
+ }
+ this.insertToGallery(a);
+ return a;
+ };
+
+ /**
+ * Sort the array using settings.comparator as comparator
+ *
+ * @param a the array to sort (it is sorted)
+ * @return the sorted array
+ */
+ JustifiedGallery.prototype.sortArray = function (a) {
+ a.sort(this.settings.sort);
+ this.insertToGallery(a);
+ return a;
+ };
+
+ /**
+ * Reset the filters removing the 'jg-filtered' class from all the entries
+ *
+ * @param a the array to reset
+ */
+ JustifiedGallery.prototype.resetFilters = function (a) {
+ for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
+ };
+
+ /**
+ * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
+ *
+ * @param a the array to filter
+ * @return the filtered array
+ */
+ JustifiedGallery.prototype.filterArray = function (a) {
+ var settings = this.settings;
+ if ($.type(settings.filter) === 'string') {
+ // Filter only keeping the entries passed in the string
+ return a.filter(function (el) {
+ var $el = $(el);
+ if ($el.is(settings.filter)) {
+ $el.removeClass('jg-filtered');
+ return true;
+ } else {
+ $el.addClass('jg-filtered').removeClass('jg-visible');
+ return false;
+ }
+ });
+ } else if ($.isFunction(settings.filter)) {
+ // Filter using the passed function
+ var filteredArr = a.filter(settings.filter);
+ for (var i = 0; i < a.length; i++) {
+ if (filteredArr.indexOf(a[i]) === -1) {
+ $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
+ } else {
+ $(a[i]).removeClass('jg-filtered');
+ }
+ }
+ return filteredArr;
+ }
+ };
+
+ /**
+ * Revert the image src to the default value.
+ */
+ JustifiedGallery.prototype.resetImgSrc = function ($img) {
+ if ($img.data('jg.originalSrcLoc') === 'src') {
+ $img.attr('src', $img.data('jg.originalSrc'));
+ } else {
+ $img.attr('src', '');
+ }
+ };
+
+ /**
+ * Destroy the Justified Gallery instance.
+ *
+ * It clears all the css properties added in the style attributes. We doesn't backup the original
+ * values for those css attributes, because it costs (performance) and because in general one
+ * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
+ * classes). Creating a backup is also difficult because JG could be called multiple times and
+ * with different style attributes.
+ */
+ JustifiedGallery.prototype.destroy = function () {
+ clearInterval(this.checkWidthIntervalId);
+ this.stopImgAnalyzerStarter();
+
+ // Get fresh entries list since filtered entries are absent in `this.entries`
+ $.each(this.getAllEntries(), $.proxy(function (_, entry) {
+ var $entry = $(entry);
+
+ // Reset entry style
+ $entry.css('width', '');
+ $entry.css('height', '');
+ $entry.css('top', '');
+ $entry.css('left', '');
+ $entry.data('jg.loaded', undefined);
+ $entry.removeClass('jg-entry jg-filtered jg-entry-visible');
+
+ // Reset image style
+ var $img = this.imgFromEntry($entry);
+ if ($img) {
+ $img.css('width', '');
+ $img.css('height', '');
+ $img.css('margin-left', '');
+ $img.css('margin-top', '');
+ this.resetImgSrc($img);
+ $img.data('jg.originalSrc', undefined);
+ $img.data('jg.originalSrcLoc', undefined);
+ $img.data('jg.src', undefined);
+ }
+
+ // Remove caption
+ this.removeCaptionEventsHandlers($entry);
+ var $caption = this.captionFromEntry($entry);
+ if ($entry.data('jg.createdCaption')) {
+ // remove also the caption element (if created by jg)
+ $entry.data('jg.createdCaption', undefined);
+ if ($caption !== null) $caption.remove();
+ } else {
+ if ($caption !== null) $caption.fadeTo(0, 1);
+ }
+
+ }, this));
+
+ this.$gallery.css('height', '');
+ this.$gallery.removeClass('justified-gallery');
+ this.$gallery.data('jg.controller', undefined);
+ this.settings.triggerEvent.call(this, 'jg.destroy');
+ };
+
+ /**
+ * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
+ *
+ * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
+ */
+ JustifiedGallery.prototype.analyzeImages = function (isForResize) {
+ for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
+ var $entry = $(this.entries[i]);
+ if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
+ var availableWidth = this.galleryWidth - 2 * this.border - (
+ (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
+ var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
+
+ this.buildingRow.entriesBuff.push($entry);
+ this.buildingRow.aspectRatio += imgAspectRatio;
+ this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
+ this.lastAnalyzedIndex = i;
+
+ if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
+ this.flushRow(false, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
+
+ if (++this.yield.flushed >= this.yield.every) {
+ this.startImgAnalyzer(isForResize);
+ return;
+ }
+ }
+ } else if ($entry.data('jg.loaded') !== 'error') {
+ return;
+ }
+ }
+
+ // Last row flush (the row is not full)
+ if (this.buildingRow.entriesBuff.length > 0) {
+ this.flushRow(true, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
+ }
+
+ if (this.isSpinnerActive()) {
+ this.stopLoadingSpinnerAnimation();
+ }
+
+ /* Stop, if there is, the timeout to start the analyzeImages.
+ This is because an image can be set loaded, and the timeout can be set,
+ but this image can be analyzed yet.
+ */
+ this.stopImgAnalyzerStarter();
+
+ this.setGalleryFinalHeight(this.galleryHeightToSet);
+
+ //On complete callback
+ this.settings.triggerEvent.call(this, isForResize ? 'jg.resize' : 'jg.complete');
+ };
+
+ /**
+ * Stops any ImgAnalyzer starter (that has an assigned timeout)
+ */
+ JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
+ this.yield.flushed = 0;
+ if (this.imgAnalyzerTimeout !== null) {
+ clearTimeout(this.imgAnalyzerTimeout);
+ this.imgAnalyzerTimeout = null;
+ }
+ };
+
+ /**
+ * Starts the image analyzer. It is not immediately called to let the browser to update the view
+ *
+ * @param isForResize specifies if the image analyzer must be called for resizing or not
+ */
+ JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
+ var that = this;
+ this.stopImgAnalyzerStarter();
+ this.imgAnalyzerTimeout = setTimeout(function () {
+ that.analyzeImages(isForResize);
+ }, 0.001); // we can't start it immediately due to a IE different behaviour
+ };
+
+ /**
+ * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
+ * because some browsers, with a 404 set complete = true.
+ *
+ * @param imageSrc the image src to load
+ * @param onLoad callback that is called when the image has been loaded
+ * @param onError callback that is called in case of an error
+ */
+ JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
+ if (!onLoad && !onError) return;
+
+ var memImage = new Image();
+ var $memImage = $(memImage);
+ if (onLoad) {
+ $memImage.one('load', function () {
+ $memImage.off('load error');
+ onLoad(memImage);
+ });
+ }
+ if (onError) {
+ $memImage.one('error', function () {
+ $memImage.off('load error');
+ onError(memImage);
+ });
+ }
+ memImage.src = imageSrc;
+ };
+
+ /**
+ * Init of Justified Gallery controlled
+ * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
+ */
+ JustifiedGallery.prototype.init = function () {
+ var imagesToLoad = false, skippedImages = false, that = this;
+ $.each(this.entries, function (index, entry) {
+ var $entry = $(entry);
+ var $image = that.imgFromEntry($entry);
+
+ $entry.addClass('jg-entry');
+
+ if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
+
+ // Link Rel global overwrite
+ if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
+
+ // Link Target global overwrite
+ if (that.settings.target !== null) $entry.attr('target', that.settings.target);
+
+ if ($image !== null) {
+
+ // Image src
+ var imageSrc = that.extractImgSrcFromImage($image);
+
+ /* If we have the height and the width, we don't wait that the image is loaded,
+ but we start directly with the justification */
+ if (that.settings.waitThumbnailsLoad === false || !imageSrc) {
+ var width = parseFloat($image.attr('width'));
+ var height = parseFloat($image.attr('height'));
+ if ($image.prop('tagName') === 'svg') {
+ width = parseFloat($image[0].getBBox().width);
+ height = parseFloat($image[0].getBBox().height);
+ }
+ if (!isNaN(width) && !isNaN(height)) {
+ $entry.data('jg.width', width);
+ $entry.data('jg.height', height);
+ $entry.data('jg.loaded', 'skipped');
+ skippedImages = true;
+ that.startImgAnalyzer(false);
+ return true; // continue
+ }
+ }
+
+ $entry.data('jg.loaded', false);
+ imagesToLoad = true;
+
+ // Spinner start
+ if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
+
+ that.onImageEvent(imageSrc, function (loadImg) { // image loaded
+ $entry.data('jg.width', loadImg.width);
+ $entry.data('jg.height', loadImg.height);
+ $entry.data('jg.loaded', true);
+ that.startImgAnalyzer(false);
+ }, function () { // image load error
+ $entry.data('jg.loaded', 'error');
+ that.startImgAnalyzer(false);
+ });
+
+ } else {
+ $entry.data('jg.loaded', true);
+ $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
+ $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
+ }
+
+ }
+
+ });
+
+ if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
+ this.checkWidth();
+ };
+
+ /**
+ * Checks that it is a valid number. If a string is passed it is converted to a number
+ *
+ * @param settingContainer the object that contains the setting (to allow the conversion)
+ * @param settingName the setting name
+ */
+ JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
+ if ($.type(settingContainer[settingName]) === 'string') {
+ settingContainer[settingName] = parseFloat(settingContainer[settingName]);
+ }
+
+ if ($.type(settingContainer[settingName]) === 'number') {
+ if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
+ } else {
+ throw settingName + ' must be a number';
+ }
+ };
+
+ /**
+ * Checks the sizeRangeSuffixes and, if necessary, converts
+ * its keys from string (e.g. old settings with 'lt100') to int.
+ */
+ JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
+ if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
+ throw 'sizeRangeSuffixes must be defined and must be an object';
+ }
+
+ var suffixRanges = [];
+ for (var rangeIdx in this.settings.sizeRangeSuffixes) {
+ if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
+ }
+
+ var newSizeRngSuffixes = { 0: '' };
+ for (var i = 0; i < suffixRanges.length; i++) {
+ if ($.type(suffixRanges[i]) === 'string') {
+ try {
+ var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
+ newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
+ } catch (e) {
+ throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
+ }
+ } else {
+ newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
+ }
+ }
+
+ this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
+ };
+
+ /**
+ * check and convert the maxRowHeight setting
+ * requires rowHeight to be already set
+ * TODO: should be always called when only rowHeight is changed
+ * @return number or null
+ */
+ JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
+ var newMaxRowHeight = null;
+ var rowHeight = this.settings.rowHeight;
+
+ if ($.type(this.settings.maxRowHeight) === 'string') {
+ if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
+ newMaxRowHeight = rowHeight * parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
+ } else {
+ newMaxRowHeight = parseFloat(this.settings.maxRowHeight);
+ }
+ } else if ($.type(this.settings.maxRowHeight) === 'number') {
+ newMaxRowHeight = this.settings.maxRowHeight;
+ } else if (this.settings.maxRowHeight === false || this.settings.maxRowHeight == null) {
+ return null;
+ } else {
+ throw 'maxRowHeight must be a number or a percentage';
+ }
+
+ // check if the converted value is not a number
+ if (isNaN(newMaxRowHeight)) throw 'invalid number for maxRowHeight';
+
+ // check values, maxRowHeight must be >= rowHeight
+ if (newMaxRowHeight < rowHeight) newMaxRowHeight = rowHeight;
+
+ return newMaxRowHeight;
+ };
+
+ /**
+ * Checks the settings
+ */
+ JustifiedGallery.prototype.checkSettings = function () {
+ this.checkSizeRangesSuffixes();
+
+ this.checkOrConvertNumber(this.settings, 'rowHeight');
+ this.checkOrConvertNumber(this.settings, 'margins');
+ this.checkOrConvertNumber(this.settings, 'border');
+ this.checkOrConvertNumber(this.settings, 'maxRowsCount');
+
+ var lastRowModes = [
+ 'justify',
+ 'nojustify',
+ 'left',
+ 'center',
+ 'right',
+ 'hide'
+ ];
+ if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
+ throw 'lastRow must be one of: ' + lastRowModes.join(', ');
+ }
+
+ this.checkOrConvertNumber(this.settings, 'justifyThreshold');
+ if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
+ throw 'justifyThreshold must be in the interval [0,1]';
+ }
+ if ($.type(this.settings.cssAnimation) !== 'boolean') {
+ throw 'cssAnimation must be a boolean';
+ }
+
+ if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
+ this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
+
+ this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
+ if (this.settings.captionSettings.visibleOpacity < 0 ||
+ this.settings.captionSettings.visibleOpacity > 1) {
+ throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
+ }
+
+ this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
+ if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
+ this.settings.captionSettings.nonVisibleOpacity > 1) {
+ throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
+ }
+
+ this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
+ this.checkOrConvertNumber(this.settings, 'refreshTime');
+ this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
+ if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
+ if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
+
+ if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
+ throw 'sort must be false or a comparison function';
+ }
+
+ if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
+ $.type(this.settings.filter) !== 'string') {
+ throw 'filter must be false, a string or a filter function';
+ }
+ };
+
+ /**
+ * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
+ * @returns {Array} sorted suffix ranges
+ */
+ JustifiedGallery.prototype.retrieveSuffixRanges = function () {
+ var suffixRanges = [];
+ for (var rangeIdx in this.settings.sizeRangeSuffixes) {
+ if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
+ }
+ suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
+ return suffixRanges;
+ };
+
+ /**
+ * Update the existing settings only changing some of them
+ *
+ * @param newSettings the new settings (or a subgroup of them)
+ */
+ JustifiedGallery.prototype.updateSettings = function (newSettings) {
+ // In this case Justified Gallery has been called again changing only some options
+ this.settings = $.extend({}, this.settings, newSettings);
+ this.checkSettings();
+
+ // As reported in the settings: negative value = same as margins, 0 = disabled
+ this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
+
+ this.maxRowHeight = this.retrieveMaxRowHeight();
+ this.suffixRanges = this.retrieveSuffixRanges();
+ };
+
+ JustifiedGallery.prototype.defaults = {
+ sizeRangeSuffixes: {}, /* e.g. Flickr configuration
+ {
+ 100: '_t', // used when longest is less than 100px
+ 240: '_m', // used when longest is between 101px and 240px
+ 320: '_n', // ...
+ 500: '',
+ 640: '_z',
+ 1024: '_b' // used as else case because it is the last
+ }
+ */
+ thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
+ path relative to a specific thumbnail size. The function should accept respectively three arguments:
+ current path, width and height */
+ rowHeight: 120, // required? required to be > 0?
+ maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
+ // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
+ // can't exceed 3 * rowHeight)
+ maxRowsCount: 0, // maximum number of rows to be displayed (0 = disabled)
+ margins: 1,
+ border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
+
+ lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
+
+ justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
+ * (i.e. lastRow setting is not considered) */
+ waitThumbnailsLoad: true,
+ captions: true,
+ cssAnimation: true,
+ imagesAnimationDuration: 500, // ignored with css animations
+ captionSettings: { // ignored with css animations
+ animationDuration: 500,
+ visibleOpacity: 0.7,
+ nonVisibleOpacity: 0.0
+ },
+ rel: null, // rewrite the rel of each analyzed links
+ target: null, // rewrite the target of all links
+ extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
+ refreshTime: 200, // time interval (in ms) to check if the page changes its width
+ refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
+ randomize: false,
+ rtl: false, // right-to-left mode
+ sort: false, /*
+ - false: to do not sort
+ - function: to sort them using the function as comparator (see Array.prototype.sort())
+ */
+ filter: false, /*
+ - false, null or undefined: for a disabled filter
+ - a string: an entry is kept if entry.is(filter string) returns true
+ see jQuery's .is() function for further information
+ - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
+ It follows the specifications of the Array.prototype.filter() function of JavaScript.
+ */
+ selector: 'a', // The selector that is used to know what are the entries of the gallery
+ imgSelector: '> img, > a > img, > svg, > a > svg', // The selector that is used to know what are the images of each entry
+ triggerEvent: function (event) { // This is called to trigger events, the default behavior is to call $.trigger
+ this.$gallery.trigger(event); // Consider that 'this' is this set to the JustifiedGallery object, so it can
+ } // access to fields such as $gallery, useful to trigger events with jQuery.
+ };
+
+
+ /**
+ * Justified Gallery plugin for jQuery
+ *
+ * Events
+ * - jg.complete : called when all the gallery has been created
+ * - jg.resize : called when the gallery has been resized
+ * - jg.rowflush : when a new row appears
+ *
+ * @param arg the action (or the settings) passed when the plugin is called
+ * @returns {*} the object itself
+ */
+ $.fn.justifiedGallery = function (arg) {
+ return this.each(function (index, gallery) {
+
+ var $gallery = $(gallery);
+ $gallery.addClass('justified-gallery');
+
+ var controller = $gallery.data('jg.controller');
+ if (typeof controller === 'undefined') {
+ // Create controller and assign it to the object data
+ if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
+ if (arg === 'destroy') return; // Just a call to an unexisting object
+ throw 'The argument must be an object';
+ }
+ controller = new JustifiedGallery($gallery, $.extend({}, JustifiedGallery.prototype.defaults, arg));
+ $gallery.data('jg.controller', controller);
+ } else if (arg === 'norewind') {
+ // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
+ // ... left to be more readable
+ } else if (arg === 'destroy') {
+ controller.destroy();
+ return;
+ } else {
+ // In this case Justified Gallery has been called again changing only some options
+ controller.updateSettings(arg);
+ controller.rewind();
+ }
+
+ // Update the entries list
+ if (!controller.updateEntries(arg === 'norewind')) return;
+
+ // Init justified gallery
+ controller.init();
+
+ });
+ };
+
+}));
\ No newline at end of file
diff --git a/public/assets/homepage/js/vendors/justified-gallery.js:Zone.Identifier b/public/assets/homepage/js/vendors/justified-gallery.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/justified-gallery.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/mapstyles.js b/public/assets/homepage/js/vendors/mapstyles.js
new file mode 100644
index 0000000..f02d9ed
--- /dev/null
+++ b/public/assets/homepage/js/vendors/mapstyles.js
@@ -0,0 +1,1100 @@
+/*!
+ Google Map Style
+!*/
+
+const Retro = [
+ {
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#ebe3cd"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#523735"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#f5f1e6"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#c9b2a6"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.land_parcel",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#dcd2be"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.land_parcel",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#ae9e90"
+ }
+ ]
+ },
+ {
+ "featureType": "landscape.natural",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#dfd2ae"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#dfd2ae"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#93817c"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "geometry.fill",
+ "stylers": [
+ {
+ "color": "#a5b076"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#447530"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#f5f1e6"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.icon",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "road.arterial",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#fdfcf8"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#f8c967"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#e9bc62"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway.controlled_access",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#e98d58"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway.controlled_access",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#db8555"
+ }
+ ]
+ },
+ {
+ "featureType": "road.local",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#806b63"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.line",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#dfd2ae"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.line",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#8f7d77"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.line",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#ebe3cd"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.station",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#dfd2ae"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "geometry.fill",
+ "stylers": [
+ {
+ "color": "#b9d3c2"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#92998d"
+ }
+ ]
+ }
+]
+
+// Standard Style
+const Standard = []
+
+// Silver Style
+const Silver = [
+ {
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#f5f5f5"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.icon",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#616161"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#f5f5f5"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.land_parcel",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#bdbdbd"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#eeeeee"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#757575"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#e5e5e5"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#9e9e9e"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#ffffff"
+ }
+ ]
+ },
+ {
+ "featureType": "road.arterial",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#757575"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#dadada"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#616161"
+ }
+ ]
+ },
+ {
+ "featureType": "road.local",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#9e9e9e"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.line",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#e5e5e5"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.station",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#eeeeee"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#c9c9c9"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#9e9e9e"
+ }
+ ]
+ }
+]
+
+// Dark Style
+const Dark = [
+ {
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#212121"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.icon",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#757575"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#212121"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#757575"
+ },
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.country",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#9e9e9e"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.land_parcel",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.locality",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#bdbdbd"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#757575"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#181818"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#616161"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#1b1b1b"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "geometry.fill",
+ "stylers": [
+ {
+ "color": "#2c2c2c"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.icon",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#8a8a8a"
+ }
+ ]
+ },
+ {
+ "featureType": "road.arterial",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#373737"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#3c3c3c"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway.controlled_access",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#4e4e4e"
+ }
+ ]
+ },
+ {
+ "featureType": "road.local",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#616161"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#757575"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#000000"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#3d3d3d"
+ }
+ ]
+ }
+]
+
+// Night Style
+const Night = [
+ {
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#242f3e"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#746855"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#242f3e"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.locality",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#d59563"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#d59563"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#263c3f"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#6b9a76"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#38414e"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#212a37"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.icon",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#9ca5b3"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#746855"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#1f2835"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#f3d19c"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#2f3948"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.station",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#d59563"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#17263c"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#515c6d"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#17263c"
+ }
+ ]
+ }
+]
+
+// Aubergine Style
+const Aubergine = [
+ {
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#1d2c4d"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#8ec3b9"
+ }
+ ]
+ },
+ {
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#1a3646"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.country",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#4b6878"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.land_parcel",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#64779e"
+ }
+ ]
+ },
+ {
+ "featureType": "administrative.province",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#4b6878"
+ }
+ ]
+ },
+ {
+ "featureType": "landscape.man_made",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#334e87"
+ }
+ ]
+ },
+ {
+ "featureType": "landscape.natural",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#023e58"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#283d6a"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#6f9ba5"
+ }
+ ]
+ },
+ {
+ "featureType": "poi",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#1d2c4d"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "geometry.fill",
+ "stylers": [
+ {
+ "color": "#023e58"
+ }
+ ]
+ },
+ {
+ "featureType": "poi.park",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#3C7680"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#304a7d"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.icon",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#98a5be"
+ }
+ ]
+ },
+ {
+ "featureType": "road",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#1d2c4d"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#2c6675"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "geometry.stroke",
+ "stylers": [
+ {
+ "color": "#255763"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#b0d5ce"
+ }
+ ]
+ },
+ {
+ "featureType": "road.highway",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#023e58"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "stylers": [
+ {
+ "visibility": "off"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#98a5be"
+ }
+ ]
+ },
+ {
+ "featureType": "transit",
+ "elementType": "labels.text.stroke",
+ "stylers": [
+ {
+ "color": "#1d2c4d"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.line",
+ "elementType": "geometry.fill",
+ "stylers": [
+ {
+ "color": "#283d6a"
+ }
+ ]
+ },
+ {
+ "featureType": "transit.station",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#3a4762"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "geometry",
+ "stylers": [
+ {
+ "color": "#0e1626"
+ }
+ ]
+ },
+ {
+ "featureType": "water",
+ "elementType": "labels.text.fill",
+ "stylers": [
+ {
+ "color": "#4e6d70"
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/public/assets/homepage/js/vendors/mapstyles.js:Zone.Identifier b/public/assets/homepage/js/vendors/mapstyles.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/mapstyles.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/parallax.js b/public/assets/homepage/js/vendors/parallax.js
new file mode 100644
index 0000000..273fbd7
--- /dev/null
+++ b/public/assets/homepage/js/vendors/parallax.js
@@ -0,0 +1,6 @@
+/*!
+ Crafto - Parallax
+ Created by ThemeZaa
+!*/
+
+!function(n){var t=n(window),o=t.height();t.resize(function(){o=t.height()}),n.fn.parallax=function(i,e,l){var r,u=n(this);function c(){var l=t.scrollTop();u.each(function(){var t=n(this),c=t.offset().top;c+r(t)l+o||(n(window).width()>1050?u.css("backgroundPosition",i+" "+(c-l)*e+"px"):u.css("backgroundPosition",""))})}u.each(function(n){u.offset().top}),(arguments.length<1||null===i)&&(i="50%"),(arguments.length<2||null===e)&&(e=.5),(arguments.length<3||null===l)&&(l=!0),(arguments.length<4||null===pos)&&(pos=0),r=l?function(n){return n.outerHeight(!0)}:function(n){return n.height()},t.bind("scroll",c).resize(c),c()},n.fn.parallaxImg=function(i,e){var l,r=n(this);function u(){var e=t.scrollTop();r.each(function(){var t=n(this),u=t.offset().top;u+l(t)e+o||(n(window).width()>1050?r.css("bottom",i/10*-(u-e)+"px"):r.css("bottom",""))})}(arguments.length<1||null===i)&&(i=1),(arguments.length<2||null===e)&&(e=!0),l=e?function(n){return n.outerHeight(!0)}:function(n){return n.height()},t.bind("scroll",u).resize(u),u()}}(jQuery);
\ No newline at end of file
diff --git a/public/assets/homepage/js/vendors/parallax.js:Zone.Identifier b/public/assets/homepage/js/vendors/parallax.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/parallax.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/parallaxLiquid.js b/public/assets/homepage/js/vendors/parallaxLiquid.js
new file mode 100644
index 0000000..b1832c9
--- /dev/null
+++ b/public/assets/homepage/js/vendors/parallaxLiquid.js
@@ -0,0 +1,77 @@
+/*!
+ Crafto - Parallax Liquid Image
+ Created by ThemeZaa
+!*/
+! function(n) {
+ var t = n(window),
+ o = t.height();
+ t.resize(function() {
+ o = t.height()
+ }), n.fn.parallaxLiquidImg = function(i, scale, scaleFraction, reverse, e) {
+ var l, r = n(this);
+ var canScale = scale ? 1 : 0;
+ var scale = scale ? scale : 1.2;
+ var scaleFraction = scaleFraction ? scaleFraction : 0.001;
+ var lastScrollPos = 0;
+ var scrollDir = '';
+ function u() {
+ var e = t.scrollTop();
+
+ r.each(function() {
+ var t = n(this),
+ u = t.offset().top,
+ tHeight = t.outerHeight(),
+ uOffesetBottom = u + tHeight;
+
+ if(e > lastScrollPos) {
+ scrollDir = 'forward';
+ } else{
+ scrollDir = 'reverse';
+ }
+
+ lastScrollPos = e;
+ if (u < n(window).height()+e && uOffesetBottom > e) {
+ if (scrollDir == 'forward') {
+ scale = scale + scaleFraction;
+ } else {
+ scale = scale - scaleFraction;
+ }
+ }
+
+ if (reverse) {
+ if (t.attr('data-parallax-scale')) {
+ u + l(t) < e || u > e + o || (
+ n(window).width() > 1050
+ ? (anime({targets: r[0], translateY: i / 6 * (u - e) + "px", scale: canScale ? scale : 1}))
+ : r.css("transform", "translateY(0px)")
+ )
+ } else {
+ u + l(t) < e || u > e + o || (
+ n(window).width() > 1050
+ ? (anime({targets: r[0], translateY: i / 20 * -(u - e) + "px", scale: canScale ? scale : 1}))
+ : r.css("transform", "translateY(0px)")
+ )
+ }
+ } else {
+ if (t.attr('data-parallax-scale')) {
+ u + l(t) < e || u > e + o || (
+ n(window).width() > 1050
+ ? (anime({targets: r[0], translateY: i / 6 * -(u - e) + "px", scale: canScale ? scale : 1}))
+ : r.css("transform", "translateY(0px)")
+ )
+ } else {
+ u + l(t) < e || u > e + o || (
+ n(window).width() > 1050
+ ? (anime({targets: r[0], translateY: i / 20 * (u - e) + "px", scale: canScale ? scale : 1}))
+ : r.css("transform", "translateY(0px)")
+ )
+ }
+ }
+ })
+ }(arguments.length < 1 || null === i) && (i = 1), (arguments.length < 2 || null === e) && (e = !0), l = e ? function(n) {
+ return n.outerHeight(!0)
+ } : function(n) {
+ return n.height()
+ }, t.bind("scroll", u).resize(u), u()
+ }
+}(jQuery);
diff --git a/public/assets/homepage/js/vendors/parallaxLiquid.js:Zone.Identifier b/public/assets/homepage/js/vendors/parallaxLiquid.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/parallaxLiquid.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/particles.js b/public/assets/homepage/js/vendors/particles.js
new file mode 100644
index 0000000..fd28bd9
--- /dev/null
+++ b/public/assets/homepage/js/vendors/particles.js
@@ -0,0 +1,1539 @@
+/*!
+ Particles
+ Version: 2.0.0
+ Plugin URL: https://vincentgarreau.com/particles.js/
+ License: Copyright Vincent Garreau - vincentgarreau.com | Licensed under MIT
+!*/
+
+var pJS = function(tag_id, params){
+
+ var canvas_el = document.querySelector('#'+tag_id+' > .particles-js-canvas-el');
+
+ /* particles.js variables with default values */
+ this.pJS = {
+ canvas: {
+ el: canvas_el,
+ w: canvas_el.offsetWidth,
+ h: canvas_el.offsetHeight
+ },
+ particles: {
+ number: {
+ value: 400,
+ density: {
+ enable: true,
+ value_area: 800
+ }
+ },
+ color: {
+ value: '#fff'
+ },
+ shape: {
+ type: 'circle',
+ stroke: {
+ width: 0,
+ color: '#ff0000'
+ },
+ polygon: {
+ nb_sides: 5
+ },
+ image: {
+ src: '',
+ width: 100,
+ height: 100
+ }
+ },
+ opacity: {
+ value: 1,
+ random: false,
+ anim: {
+ enable: false,
+ speed: 2,
+ opacity_min: 0,
+ sync: false
+ }
+ },
+ size: {
+ value: 20,
+ random: false,
+ anim: {
+ enable: false,
+ speed: 20,
+ size_min: 0,
+ sync: false
+ }
+ },
+ line_linked: {
+ enable: true,
+ distance: 100,
+ color: '#fff',
+ opacity: 1,
+ width: 1
+ },
+ move: {
+ enable: true,
+ speed: 2,
+ direction: 'none',
+ random: false,
+ straight: false,
+ out_mode: 'out',
+ bounce: false,
+ attract: {
+ enable: false,
+ rotateX: 3000,
+ rotateY: 3000
+ }
+ },
+ array: []
+ },
+ interactivity: {
+ detect_on: 'canvas',
+ events: {
+ onhover: {
+ enable: true,
+ mode: 'grab'
+ },
+ onclick: {
+ enable: true,
+ mode: 'push'
+ },
+ resize: true
+ },
+ modes: {
+ grab:{
+ distance: 100,
+ line_linked:{
+ opacity: 1
+ }
+ },
+ bubble:{
+ distance: 200,
+ size: 80,
+ duration: 0.4
+ },
+ repulse:{
+ distance: 200,
+ duration: 0.4
+ },
+ push:{
+ particles_nb: 4
+ },
+ remove:{
+ particles_nb: 2
+ }
+ },
+ mouse:{}
+ },
+ retina_detect: false,
+ fn: {
+ interact: {},
+ modes: {},
+ vendors:{}
+ },
+ tmp: {}
+ };
+
+ var pJS = this.pJS;
+
+ /* params settings */
+ if(params){
+ Object.deepExtend(pJS, params);
+ }
+
+ pJS.tmp.obj = {
+ size_value: pJS.particles.size.value,
+ size_anim_speed: pJS.particles.size.anim.speed,
+ move_speed: pJS.particles.move.speed,
+ line_linked_distance: pJS.particles.line_linked.distance,
+ line_linked_width: pJS.particles.line_linked.width,
+ mode_grab_distance: pJS.interactivity.modes.grab.distance,
+ mode_bubble_distance: pJS.interactivity.modes.bubble.distance,
+ mode_bubble_size: pJS.interactivity.modes.bubble.size,
+ mode_repulse_distance: pJS.interactivity.modes.repulse.distance
+ };
+
+
+ pJS.fn.retinaInit = function(){
+
+ if(pJS.retina_detect && window.devicePixelRatio > 1){
+ pJS.canvas.pxratio = window.devicePixelRatio;
+ pJS.tmp.retina = true;
+ }
+ else{
+ pJS.canvas.pxratio = 1;
+ pJS.tmp.retina = false;
+ }
+
+ pJS.canvas.w = pJS.canvas.el.offsetWidth * pJS.canvas.pxratio;
+ pJS.canvas.h = pJS.canvas.el.offsetHeight * pJS.canvas.pxratio;
+
+ pJS.particles.size.value = pJS.tmp.obj.size_value * pJS.canvas.pxratio;
+ pJS.particles.size.anim.speed = pJS.tmp.obj.size_anim_speed * pJS.canvas.pxratio;
+ pJS.particles.move.speed = pJS.tmp.obj.move_speed * pJS.canvas.pxratio;
+ pJS.particles.line_linked.distance = pJS.tmp.obj.line_linked_distance * pJS.canvas.pxratio;
+ pJS.interactivity.modes.grab.distance = pJS.tmp.obj.mode_grab_distance * pJS.canvas.pxratio;
+ pJS.interactivity.modes.bubble.distance = pJS.tmp.obj.mode_bubble_distance * pJS.canvas.pxratio;
+ pJS.particles.line_linked.width = pJS.tmp.obj.line_linked_width * pJS.canvas.pxratio;
+ pJS.interactivity.modes.bubble.size = pJS.tmp.obj.mode_bubble_size * pJS.canvas.pxratio;
+ pJS.interactivity.modes.repulse.distance = pJS.tmp.obj.mode_repulse_distance * pJS.canvas.pxratio;
+
+ };
+
+
+
+ /* ---------- pJS functions - canvas ------------ */
+
+ pJS.fn.canvasInit = function(){
+ pJS.canvas.ctx = pJS.canvas.el.getContext('2d');
+ };
+
+ pJS.fn.canvasSize = function(){
+
+ pJS.canvas.el.width = pJS.canvas.w;
+ pJS.canvas.el.height = pJS.canvas.h;
+
+ if(pJS && pJS.interactivity.events.resize){
+
+ window.addEventListener('resize', function(){
+
+ pJS.canvas.w = pJS.canvas.el.offsetWidth;
+ pJS.canvas.h = pJS.canvas.el.offsetHeight;
+
+ /* resize canvas */
+ if(pJS.tmp.retina){
+ pJS.canvas.w *= pJS.canvas.pxratio;
+ pJS.canvas.h *= pJS.canvas.pxratio;
+ }
+
+ pJS.canvas.el.width = pJS.canvas.w;
+ pJS.canvas.el.height = pJS.canvas.h;
+
+ /* repaint canvas on anim disabled */
+ if(!pJS.particles.move.enable){
+ pJS.fn.particlesEmpty();
+ pJS.fn.particlesCreate();
+ pJS.fn.particlesDraw();
+ pJS.fn.vendors.densityAutoParticles();
+ }
+
+ /* density particles enabled */
+ pJS.fn.vendors.densityAutoParticles();
+
+ });
+
+ }
+
+ };
+
+
+ pJS.fn.canvasPaint = function(){
+ pJS.canvas.ctx.fillRect(0, 0, pJS.canvas.w, pJS.canvas.h);
+ };
+
+ pJS.fn.canvasClear = function(){
+ pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
+ };
+
+
+ /* --------- pJS functions - particles ----------- */
+
+ pJS.fn.particle = function(color, opacity, position){
+
+ /* size */
+ this.radius = (pJS.particles.size.random ? Math.random() : 1) * pJS.particles.size.value;
+ if(pJS.particles.size.anim.enable){
+ this.size_status = false;
+ this.vs = pJS.particles.size.anim.speed / 100;
+ if(!pJS.particles.size.anim.sync){
+ this.vs = this.vs * Math.random();
+ }
+ }
+
+ /* position */
+ this.x = position ? position.x : Math.random() * pJS.canvas.w;
+ this.y = position ? position.y : Math.random() * pJS.canvas.h;
+
+ /* check position - into the canvas */
+ if(this.x > pJS.canvas.w - this.radius*2) this.x = this.x - this.radius;
+ else if(this.x < this.radius*2) this.x = this.x + this.radius;
+ if(this.y > pJS.canvas.h - this.radius*2) this.y = this.y - this.radius;
+ else if(this.y < this.radius*2) this.y = this.y + this.radius;
+
+ /* check position - avoid overlap */
+ if(pJS.particles.move.bounce){
+ pJS.fn.vendors.checkOverlap(this, position);
+ }
+
+ /* color */
+ this.color = {};
+ if(typeof(color.value) == 'object'){
+
+ if(color.value instanceof Array){
+ var color_selected = color.value[Math.floor(Math.random() * pJS.particles.color.value.length)];
+ this.color.rgb = hexToRgb(color_selected);
+ }else{
+ if(color.value.r != undefined && color.value.g != undefined && color.value.b != undefined){
+ this.color.rgb = {
+ r: color.value.r,
+ g: color.value.g,
+ b: color.value.b
+ }
+ }
+ if(color.value.h != undefined && color.value.s != undefined && color.value.l != undefined){
+ this.color.hsl = {
+ h: color.value.h,
+ s: color.value.s,
+ l: color.value.l
+ }
+ }
+ }
+
+ }
+ else if(color.value == 'random'){
+ this.color.rgb = {
+ r: (Math.floor(Math.random() * (255 - 0 + 1)) + 0),
+ g: (Math.floor(Math.random() * (255 - 0 + 1)) + 0),
+ b: (Math.floor(Math.random() * (255 - 0 + 1)) + 0)
+ }
+ }
+ else if(typeof(color.value) == 'string'){
+ this.color = color;
+ this.color.rgb = hexToRgb(this.color.value);
+ }
+
+ /* opacity */
+ this.opacity = (pJS.particles.opacity.random ? Math.random() : 1) * pJS.particles.opacity.value;
+ if(pJS.particles.opacity.anim.enable){
+ this.opacity_status = false;
+ this.vo = pJS.particles.opacity.anim.speed / 100;
+ if(!pJS.particles.opacity.anim.sync){
+ this.vo = this.vo * Math.random();
+ }
+ }
+
+ /* animation - velocity for speed */
+ var velbase = {}
+ switch(pJS.particles.move.direction){
+ case 'top':
+ velbase = { x:0, y:-1 };
+ break;
+ case 'top-right':
+ velbase = { x:0.5, y:-0.5 };
+ break;
+ case 'right':
+ velbase = { x:1, y:-0 };
+ break;
+ case 'bottom-right':
+ velbase = { x:0.5, y:0.5 };
+ break;
+ case 'bottom':
+ velbase = { x:0, y:1 };
+ break;
+ case 'bottom-left':
+ velbase = { x:-0.5, y:1 };
+ break;
+ case 'left':
+ velbase = { x:-1, y:0 };
+ break;
+ case 'top-left':
+ velbase = { x:-0.5, y:-0.5 };
+ break;
+ default:
+ velbase = { x:0, y:0 };
+ break;
+ }
+
+ if(pJS.particles.move.straight){
+ this.vx = velbase.x;
+ this.vy = velbase.y;
+ if(pJS.particles.move.random){
+ this.vx = this.vx * (Math.random());
+ this.vy = this.vy * (Math.random());
+ }
+ }else{
+ this.vx = velbase.x + Math.random()-0.5;
+ this.vy = velbase.y + Math.random()-0.5;
+ }
+
+ // var theta = 2.0 * Math.PI * Math.random();
+ // this.vx = Math.cos(theta);
+ // this.vy = Math.sin(theta);
+
+ this.vx_i = this.vx;
+ this.vy_i = this.vy;
+
+
+
+ /* if shape is image */
+
+ var shape_type = pJS.particles.shape.type;
+ if(typeof(shape_type) == 'object'){
+ if(shape_type instanceof Array){
+ var shape_selected = shape_type[Math.floor(Math.random() * shape_type.length)];
+ this.shape = shape_selected;
+ }
+ }else{
+ this.shape = shape_type;
+ }
+
+ if(this.shape == 'image'){
+ var sh = pJS.particles.shape;
+ this.img = {
+ src: sh.image.src,
+ ratio: sh.image.width / sh.image.height
+ }
+ if(!this.img.ratio) this.img.ratio = 1;
+ if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg != undefined){
+ pJS.fn.vendors.createSvgImg(this);
+ if(pJS.tmp.pushing){
+ this.img.loaded = false;
+ }
+ }
+ }
+
+
+
+ };
+
+
+ pJS.fn.particle.prototype.draw = function() {
+
+ var p = this;
+
+ if(p.radius_bubble != undefined){
+ var radius = p.radius_bubble;
+ }else{
+ var radius = p.radius;
+ }
+
+ if(p.opacity_bubble != undefined){
+ var opacity = p.opacity_bubble;
+ }else{
+ var opacity = p.opacity;
+ }
+
+ if(p.color.rgb){
+ var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+opacity+')';
+ }else{
+ var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+opacity+')';
+ }
+
+ pJS.canvas.ctx.fillStyle = color_value;
+ pJS.canvas.ctx.beginPath();
+
+ switch(p.shape){
+
+ case 'circle':
+ pJS.canvas.ctx.arc(p.x, p.y, radius, 0, Math.PI * 2, false);
+ break;
+
+ case 'edge':
+ pJS.canvas.ctx.rect(p.x-radius, p.y-radius, radius*2, radius*2);
+ break;
+
+ case 'triangle':
+ pJS.fn.vendors.drawShape(pJS.canvas.ctx, p.x-radius, p.y+radius / 1.66, radius*2, 3, 2);
+ break;
+
+ case 'polygon':
+ pJS.fn.vendors.drawShape(
+ pJS.canvas.ctx,
+ p.x - radius / (pJS.particles.shape.polygon.nb_sides/3.5), // startX
+ p.y - radius / (2.66/3.5), // startY
+ radius*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength
+ pJS.particles.shape.polygon.nb_sides, // sideCountNumerator
+ 1 // sideCountDenominator
+ );
+ break;
+
+ case 'star':
+ pJS.fn.vendors.drawShape(
+ pJS.canvas.ctx,
+ p.x - radius*2 / (pJS.particles.shape.polygon.nb_sides/4), // startX
+ p.y - radius / (2*2.66/3.5), // startY
+ radius*2*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength
+ pJS.particles.shape.polygon.nb_sides, // sideCountNumerator
+ 2 // sideCountDenominator
+ );
+ break;
+
+ case 'image':
+
+ function draw(){
+ pJS.canvas.ctx.drawImage(
+ img_obj,
+ p.x-radius,
+ p.y-radius,
+ radius*2,
+ radius*2 / p.img.ratio
+ );
+ }
+
+ if(pJS.tmp.img_type == 'svg'){
+ var img_obj = p.img.obj;
+ }else{
+ var img_obj = pJS.tmp.img_obj;
+ }
+
+ if(img_obj){
+ draw();
+ }
+
+ break;
+
+ }
+
+ pJS.canvas.ctx.closePath();
+
+ if(pJS.particles.shape.stroke.width > 0){
+ pJS.canvas.ctx.strokeStyle = pJS.particles.shape.stroke.color;
+ pJS.canvas.ctx.lineWidth = pJS.particles.shape.stroke.width;
+ pJS.canvas.ctx.stroke();
+ }
+
+ pJS.canvas.ctx.fill();
+
+ };
+
+
+ pJS.fn.particlesCreate = function(){
+ for(var i = 0; i < pJS.particles.number.value; i++) {
+ pJS.particles.array.push(new pJS.fn.particle(pJS.particles.color, pJS.particles.opacity.value));
+ }
+ };
+
+ pJS.fn.particlesUpdate = function(){
+
+ for(var i = 0; i < pJS.particles.array.length; i++){
+
+ /* the particle */
+ var p = pJS.particles.array[i];
+
+ // var d = ( dx = pJS.interactivity.mouse.click_pos_x - p.x ) * dx + ( dy = pJS.interactivity.mouse.click_pos_y - p.y ) * dy;
+ // var f = -BANG_SIZE / d;
+ // if ( d < BANG_SIZE ) {
+ // var t = Math.atan2( dy, dx );
+ // p.vx = f * Math.cos(t);
+ // p.vy = f * Math.sin(t);
+ // }
+
+ /* move the particle */
+ if(pJS.particles.move.enable){
+ var ms = pJS.particles.move.speed/2;
+ p.x += p.vx * ms;
+ p.y += p.vy * ms;
+ }
+
+ /* change opacity status */
+ if(pJS.particles.opacity.anim.enable) {
+ if(p.opacity_status == true) {
+ if(p.opacity >= pJS.particles.opacity.value) p.opacity_status = false;
+ p.opacity += p.vo;
+ }else {
+ if(p.opacity <= pJS.particles.opacity.anim.opacity_min) p.opacity_status = true;
+ p.opacity -= p.vo;
+ }
+ if(p.opacity < 0) p.opacity = 0;
+ }
+
+ /* change size */
+ if(pJS.particles.size.anim.enable){
+ if(p.size_status == true){
+ if(p.radius >= pJS.particles.size.value) p.size_status = false;
+ p.radius += p.vs;
+ }else{
+ if(p.radius <= pJS.particles.size.anim.size_min) p.size_status = true;
+ p.radius -= p.vs;
+ }
+ if(p.radius < 0) p.radius = 0;
+ }
+
+ /* change particle position if it is out of canvas */
+ if(pJS.particles.move.out_mode == 'bounce'){
+ var new_pos = {
+ x_left: p.radius,
+ x_right: pJS.canvas.w,
+ y_top: p.radius,
+ y_bottom: pJS.canvas.h
+ }
+ }else{
+ var new_pos = {
+ x_left: -p.radius,
+ x_right: pJS.canvas.w + p.radius,
+ y_top: -p.radius,
+ y_bottom: pJS.canvas.h + p.radius
+ }
+ }
+
+ if(p.x - p.radius > pJS.canvas.w){
+ p.x = new_pos.x_left;
+ p.y = Math.random() * pJS.canvas.h;
+ }
+ else if(p.x + p.radius < 0){
+ p.x = new_pos.x_right;
+ p.y = Math.random() * pJS.canvas.h;
+ }
+ if(p.y - p.radius > pJS.canvas.h){
+ p.y = new_pos.y_top;
+ p.x = Math.random() * pJS.canvas.w;
+ }
+ else if(p.y + p.radius < 0){
+ p.y = new_pos.y_bottom;
+ p.x = Math.random() * pJS.canvas.w;
+ }
+
+ /* out of canvas modes */
+ switch(pJS.particles.move.out_mode){
+ case 'bounce':
+ if (p.x + p.radius > pJS.canvas.w) p.vx = -p.vx;
+ else if (p.x - p.radius < 0) p.vx = -p.vx;
+ if (p.y + p.radius > pJS.canvas.h) p.vy = -p.vy;
+ else if (p.y - p.radius < 0) p.vy = -p.vy;
+ break;
+ }
+
+ /* events */
+ if(isInArray('grab', pJS.interactivity.events.onhover.mode)){
+ pJS.fn.modes.grabParticle(p);
+ }
+
+ if(isInArray('bubble', pJS.interactivity.events.onhover.mode) || isInArray('bubble', pJS.interactivity.events.onclick.mode)){
+ pJS.fn.modes.bubbleParticle(p);
+ }
+
+ if(isInArray('repulse', pJS.interactivity.events.onhover.mode) || isInArray('repulse', pJS.interactivity.events.onclick.mode)){
+ pJS.fn.modes.repulseParticle(p);
+ }
+
+ /* interaction auto between particles */
+ if(pJS.particles.line_linked.enable || pJS.particles.move.attract.enable){
+ for(var j = i + 1; j < pJS.particles.array.length; j++){
+ var p2 = pJS.particles.array[j];
+
+ /* link particles */
+ if(pJS.particles.line_linked.enable){
+ pJS.fn.interact.linkParticles(p,p2);
+ }
+
+ /* attract particles */
+ if(pJS.particles.move.attract.enable){
+ pJS.fn.interact.attractParticles(p,p2);
+ }
+
+ /* bounce particles */
+ if(pJS.particles.move.bounce){
+ pJS.fn.interact.bounceParticles(p,p2);
+ }
+
+ }
+ }
+
+
+ }
+
+ };
+
+ pJS.fn.particlesDraw = function(){
+
+ /* clear canvas */
+ pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h);
+
+ /* update each particles param */
+ pJS.fn.particlesUpdate();
+
+ /* draw each particle */
+ for(var i = 0; i < pJS.particles.array.length; i++){
+ var p = pJS.particles.array[i];
+ p.draw();
+ }
+
+ };
+
+ pJS.fn.particlesEmpty = function(){
+ pJS.particles.array = [];
+ };
+
+ pJS.fn.particlesRefresh = function(){
+
+ /* init all */
+ cancelRequestAnimFrame(pJS.fn.checkAnimFrame);
+ cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+ pJS.tmp.source_svg = undefined;
+ pJS.tmp.img_obj = undefined;
+ pJS.tmp.count_svg = 0;
+ pJS.fn.particlesEmpty();
+ pJS.fn.canvasClear();
+
+ /* restart */
+ pJS.fn.vendors.start();
+
+ };
+
+
+ /* ---------- pJS functions - particles interaction ------------ */
+
+ pJS.fn.interact.linkParticles = function(p1, p2){
+
+ var dx = p1.x - p2.x,
+ dy = p1.y - p2.y,
+ dist = Math.sqrt(dx*dx + dy*dy);
+
+ /* draw a line between p1 and p2 if the distance between them is under the config distance */
+ if(dist <= pJS.particles.line_linked.distance){
+
+ var opacity_line = pJS.particles.line_linked.opacity - (dist / (1/pJS.particles.line_linked.opacity)) / pJS.particles.line_linked.distance;
+
+ if(opacity_line > 0){
+
+ /* style */
+ var color_line = pJS.particles.line_linked.color_rgb_line;
+ pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
+ pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
+ //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
+
+ /* path */
+ pJS.canvas.ctx.beginPath();
+ pJS.canvas.ctx.moveTo(p1.x, p1.y);
+ pJS.canvas.ctx.lineTo(p2.x, p2.y);
+ pJS.canvas.ctx.stroke();
+ pJS.canvas.ctx.closePath();
+
+ }
+
+ }
+
+ };
+
+
+ pJS.fn.interact.attractParticles = function(p1, p2){
+
+ /* condensed particles */
+ var dx = p1.x - p2.x,
+ dy = p1.y - p2.y,
+ dist = Math.sqrt(dx*dx + dy*dy);
+
+ if(dist <= pJS.particles.line_linked.distance){
+
+ var ax = dx/(pJS.particles.move.attract.rotateX*1000),
+ ay = dy/(pJS.particles.move.attract.rotateY*1000);
+
+ p1.vx -= ax;
+ p1.vy -= ay;
+
+ p2.vx += ax;
+ p2.vy += ay;
+
+ }
+
+
+ }
+
+
+ pJS.fn.interact.bounceParticles = function(p1, p2){
+
+ var dx = p1.x - p2.x,
+ dy = p1.y - p2.y,
+ dist = Math.sqrt(dx*dx + dy*dy),
+ dist_p = p1.radius+p2.radius;
+
+ if(dist <= dist_p){
+ p1.vx = -p1.vx;
+ p1.vy = -p1.vy;
+
+ p2.vx = -p2.vx;
+ p2.vy = -p2.vy;
+ }
+
+ }
+
+
+ /* ---------- pJS functions - modes events ------------ */
+
+ pJS.fn.modes.pushParticles = function(nb, pos){
+
+ pJS.tmp.pushing = true;
+
+ for(var i = 0; i < nb; i++){
+ pJS.particles.array.push(
+ new pJS.fn.particle(
+ pJS.particles.color,
+ pJS.particles.opacity.value,
+ {
+ 'x': pos ? pos.pos_x : Math.random() * pJS.canvas.w,
+ 'y': pos ? pos.pos_y : Math.random() * pJS.canvas.h
+ }
+ )
+ )
+ if(i == nb-1){
+ if(!pJS.particles.move.enable){
+ pJS.fn.particlesDraw();
+ }
+ pJS.tmp.pushing = false;
+ }
+ }
+
+ };
+
+
+ pJS.fn.modes.removeParticles = function(nb){
+
+ pJS.particles.array.splice(0, nb);
+ if(!pJS.particles.move.enable){
+ pJS.fn.particlesDraw();
+ }
+
+ };
+
+
+ pJS.fn.modes.bubbleParticle = function(p){
+
+ /* on hover event */
+ if(pJS.interactivity.events.onhover.enable && isInArray('bubble', pJS.interactivity.events.onhover.mode)){
+
+ var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
+ dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
+ dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse),
+ ratio = 1 - dist_mouse / pJS.interactivity.modes.bubble.distance;
+
+ function init(){
+ p.opacity_bubble = p.opacity;
+ p.radius_bubble = p.radius;
+ }
+
+ /* mousemove - check ratio */
+ if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
+
+ if(ratio >= 0 && pJS.interactivity.status == 'mousemove'){
+
+ /* size */
+ if(pJS.interactivity.modes.bubble.size != pJS.particles.size.value){
+
+ if(pJS.interactivity.modes.bubble.size > pJS.particles.size.value){
+ var size = p.radius + (pJS.interactivity.modes.bubble.size*ratio);
+ if(size >= 0){
+ p.radius_bubble = size;
+ }
+ }else{
+ var dif = p.radius - pJS.interactivity.modes.bubble.size,
+ size = p.radius - (dif*ratio);
+ if(size > 0){
+ p.radius_bubble = size;
+ }else{
+ p.radius_bubble = 0;
+ }
+ }
+
+ }
+
+ /* opacity */
+ if(pJS.interactivity.modes.bubble.opacity != pJS.particles.opacity.value){
+
+ if(pJS.interactivity.modes.bubble.opacity > pJS.particles.opacity.value){
+ var opacity = pJS.interactivity.modes.bubble.opacity*ratio;
+ if(opacity > p.opacity && opacity <= pJS.interactivity.modes.bubble.opacity){
+ p.opacity_bubble = opacity;
+ }
+ }else{
+ var opacity = p.opacity - (pJS.particles.opacity.value-pJS.interactivity.modes.bubble.opacity)*ratio;
+ if(opacity < p.opacity && opacity >= pJS.interactivity.modes.bubble.opacity){
+ p.opacity_bubble = opacity;
+ }
+ }
+
+ }
+
+ }
+
+ }else{
+ init();
+ }
+
+
+ /* mouseleave */
+ if(pJS.interactivity.status == 'mouseleave'){
+ init();
+ }
+
+ }
+
+ /* on click event */
+ else if(pJS.interactivity.events.onclick.enable && isInArray('bubble', pJS.interactivity.events.onclick.mode)){
+
+
+ if(pJS.tmp.bubble_clicking){
+ var dx_mouse = p.x - pJS.interactivity.mouse.click_pos_x,
+ dy_mouse = p.y - pJS.interactivity.mouse.click_pos_y,
+ dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse),
+ time_spent = (new Date().getTime() - pJS.interactivity.mouse.click_time)/1000;
+
+ if(time_spent > pJS.interactivity.modes.bubble.duration){
+ pJS.tmp.bubble_duration_end = true;
+ }
+
+ if(time_spent > pJS.interactivity.modes.bubble.duration*2){
+ pJS.tmp.bubble_clicking = false;
+ pJS.tmp.bubble_duration_end = false;
+ }
+ }
+
+
+ function process(bubble_param, particles_param, p_obj_bubble, p_obj, id){
+
+ if(bubble_param != particles_param){
+
+ if(!pJS.tmp.bubble_duration_end){
+ if(dist_mouse <= pJS.interactivity.modes.bubble.distance){
+ if(p_obj_bubble != undefined) var obj = p_obj_bubble;
+ else var obj = p_obj;
+ if(obj != bubble_param){
+ var value = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration);
+ if(id == 'size') p.radius_bubble = value;
+ if(id == 'opacity') p.opacity_bubble = value;
+ }
+ }else{
+ if(id == 'size') p.radius_bubble = undefined;
+ if(id == 'opacity') p.opacity_bubble = undefined;
+ }
+ }else{
+ if(p_obj_bubble != undefined){
+ var value_tmp = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration),
+ dif = bubble_param - value_tmp;
+ value = bubble_param + dif;
+ if(id == 'size') p.radius_bubble = value;
+ if(id == 'opacity') p.opacity_bubble = value;
+ }
+ }
+
+ }
+
+ }
+
+ if(pJS.tmp.bubble_clicking){
+ /* size */
+ process(pJS.interactivity.modes.bubble.size, pJS.particles.size.value, p.radius_bubble, p.radius, 'size');
+ /* opacity */
+ process(pJS.interactivity.modes.bubble.opacity, pJS.particles.opacity.value, p.opacity_bubble, p.opacity, 'opacity');
+ }
+
+ }
+
+ };
+
+
+ pJS.fn.modes.repulseParticle = function(p){
+
+ if(pJS.interactivity.events.onhover.enable && isInArray('repulse', pJS.interactivity.events.onhover.mode) && pJS.interactivity.status == 'mousemove') {
+
+ var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
+ dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
+ dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
+
+ var normVec = {x: dx_mouse/dist_mouse, y: dy_mouse/dist_mouse},
+ repulseRadius = pJS.interactivity.modes.repulse.distance,
+ velocity = 100,
+ repulseFactor = clamp((1/repulseRadius)*(-1*Math.pow(dist_mouse/repulseRadius,2)+1)*repulseRadius*velocity, 0, 50);
+
+ var pos = {
+ x: p.x + normVec.x * repulseFactor,
+ y: p.y + normVec.y * repulseFactor
+ }
+
+ if(pJS.particles.move.out_mode == 'bounce'){
+ if(pos.x - p.radius > 0 && pos.x + p.radius < pJS.canvas.w) p.x = pos.x;
+ if(pos.y - p.radius > 0 && pos.y + p.radius < pJS.canvas.h) p.y = pos.y;
+ }else{
+ p.x = pos.x;
+ p.y = pos.y;
+ }
+
+ }
+
+
+ else if(pJS.interactivity.events.onclick.enable && isInArray('repulse', pJS.interactivity.events.onclick.mode)) {
+
+ if(!pJS.tmp.repulse_finish){
+ pJS.tmp.repulse_count++;
+ if(pJS.tmp.repulse_count == pJS.particles.array.length){
+ pJS.tmp.repulse_finish = true;
+ }
+ }
+
+ if(pJS.tmp.repulse_clicking){
+
+ var repulseRadius = Math.pow(pJS.interactivity.modes.repulse.distance/6, 3);
+
+ var dx = pJS.interactivity.mouse.click_pos_x - p.x,
+ dy = pJS.interactivity.mouse.click_pos_y - p.y,
+ d = dx*dx + dy*dy;
+
+ var force = -repulseRadius / d * 1;
+
+ function process(){
+
+ var f = Math.atan2(dy,dx);
+ p.vx = force * Math.cos(f);
+ p.vy = force * Math.sin(f);
+
+ if(pJS.particles.move.out_mode == 'bounce'){
+ var pos = {
+ x: p.x + p.vx,
+ y: p.y + p.vy
+ }
+ if (pos.x + p.radius > pJS.canvas.w) p.vx = -p.vx;
+ else if (pos.x - p.radius < 0) p.vx = -p.vx;
+ if (pos.y + p.radius > pJS.canvas.h) p.vy = -p.vy;
+ else if (pos.y - p.radius < 0) p.vy = -p.vy;
+ }
+
+ }
+
+ // default
+ if(d <= repulseRadius){
+ process();
+ }
+
+ // bang - slow motion mode
+ // if(!pJS.tmp.repulse_finish){
+ // if(d <= repulseRadius){
+ // process();
+ // }
+ // }else{
+ // process();
+ // }
+
+
+ }else{
+
+ if(pJS.tmp.repulse_clicking == false){
+
+ p.vx = p.vx_i;
+ p.vy = p.vy_i;
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ pJS.fn.modes.grabParticle = function(p){
+
+ if(pJS.interactivity.events.onhover.enable && pJS.interactivity.status == 'mousemove'){
+
+ var dx_mouse = p.x - pJS.interactivity.mouse.pos_x,
+ dy_mouse = p.y - pJS.interactivity.mouse.pos_y,
+ dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse);
+
+ /* draw a line between the cursor and the particle if the distance between them is under the config distance */
+ if(dist_mouse <= pJS.interactivity.modes.grab.distance){
+
+ var opacity_line = pJS.interactivity.modes.grab.line_linked.opacity - (dist_mouse / (1/pJS.interactivity.modes.grab.line_linked.opacity)) / pJS.interactivity.modes.grab.distance;
+
+ if(opacity_line > 0){
+
+ /* style */
+ var color_line = pJS.particles.line_linked.color_rgb_line;
+ pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')';
+ pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width;
+ //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */
+
+ /* path */
+ pJS.canvas.ctx.beginPath();
+ pJS.canvas.ctx.moveTo(p.x, p.y);
+ pJS.canvas.ctx.lineTo(pJS.interactivity.mouse.pos_x, pJS.interactivity.mouse.pos_y);
+ pJS.canvas.ctx.stroke();
+ pJS.canvas.ctx.closePath();
+
+ }
+
+ }
+
+ }
+
+ };
+
+
+
+ /* ---------- pJS functions - vendors ------------ */
+
+ pJS.fn.vendors.eventsListeners = function(){
+
+ /* events target element */
+ if(pJS.interactivity.detect_on == 'window'){
+ pJS.interactivity.el = window;
+ }else{
+ pJS.interactivity.el = pJS.canvas.el;
+ }
+
+
+ /* detect mouse pos - on hover / click event */
+ if(pJS.interactivity.events.onhover.enable || pJS.interactivity.events.onclick.enable){
+
+ /* el on mousemove */
+ pJS.interactivity.el.addEventListener('mousemove', function(e){
+
+ if(pJS.interactivity.el == window){
+ var pos_x = e.clientX,
+ pos_y = e.clientY;
+ }
+ else{
+ var pos_x = e.offsetX || e.clientX,
+ pos_y = e.offsetY || e.clientY;
+ }
+
+ pJS.interactivity.mouse.pos_x = pos_x;
+ pJS.interactivity.mouse.pos_y = pos_y;
+
+ if(pJS.tmp.retina){
+ pJS.interactivity.mouse.pos_x *= pJS.canvas.pxratio;
+ pJS.interactivity.mouse.pos_y *= pJS.canvas.pxratio;
+ }
+
+ pJS.interactivity.status = 'mousemove';
+
+ });
+
+ /* el on onmouseleave */
+ pJS.interactivity.el.addEventListener('mouseleave', function(e){
+
+ pJS.interactivity.mouse.pos_x = null;
+ pJS.interactivity.mouse.pos_y = null;
+ pJS.interactivity.status = 'mouseleave';
+
+ });
+
+ }
+
+ /* on click event */
+ if(pJS.interactivity.events.onclick.enable){
+
+ pJS.interactivity.el.addEventListener('click', function(){
+
+ pJS.interactivity.mouse.click_pos_x = pJS.interactivity.mouse.pos_x;
+ pJS.interactivity.mouse.click_pos_y = pJS.interactivity.mouse.pos_y;
+ pJS.interactivity.mouse.click_time = new Date().getTime();
+
+ if(pJS.interactivity.events.onclick.enable){
+
+ switch(pJS.interactivity.events.onclick.mode){
+
+ case 'push':
+ if(pJS.particles.move.enable){
+ pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse);
+ }else{
+ if(pJS.interactivity.modes.push.particles_nb == 1){
+ pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse);
+ }
+ else if(pJS.interactivity.modes.push.particles_nb > 1){
+ pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb);
+ }
+ }
+ break;
+
+ case 'remove':
+ pJS.fn.modes.removeParticles(pJS.interactivity.modes.remove.particles_nb);
+ break;
+
+ case 'bubble':
+ pJS.tmp.bubble_clicking = true;
+ break;
+
+ case 'repulse':
+ pJS.tmp.repulse_clicking = true;
+ pJS.tmp.repulse_count = 0;
+ pJS.tmp.repulse_finish = false;
+ setTimeout(function(){
+ pJS.tmp.repulse_clicking = false;
+ }, pJS.interactivity.modes.repulse.duration*1000)
+ break;
+
+ }
+
+ }
+
+ });
+
+ }
+
+
+ };
+
+ pJS.fn.vendors.densityAutoParticles = function(){
+
+ if(pJS.particles.number.density.enable){
+
+ /* calc area */
+ var area = pJS.canvas.el.width * pJS.canvas.el.height / 1000;
+ if(pJS.tmp.retina){
+ area = area/(pJS.canvas.pxratio*2);
+ }
+
+ /* calc number of particles based on density area */
+ var nb_particles = area * pJS.particles.number.value / pJS.particles.number.density.value_area;
+
+ /* add or remove X particles */
+ var missing_particles = pJS.particles.array.length - nb_particles;
+ if(missing_particles < 0) pJS.fn.modes.pushParticles(Math.abs(missing_particles));
+ else pJS.fn.modes.removeParticles(missing_particles);
+
+ }
+
+ };
+
+
+ pJS.fn.vendors.checkOverlap = function(p1, position){
+ for(var i = 0; i < pJS.particles.array.length; i++){
+ var p2 = pJS.particles.array[i];
+
+ var dx = p1.x - p2.x,
+ dy = p1.y - p2.y,
+ dist = Math.sqrt(dx*dx + dy*dy);
+
+ if(dist <= p1.radius + p2.radius){
+ p1.x = position ? position.x : Math.random() * pJS.canvas.w;
+ p1.y = position ? position.y : Math.random() * pJS.canvas.h;
+ pJS.fn.vendors.checkOverlap(p1);
+ }
+ }
+ };
+
+
+ pJS.fn.vendors.createSvgImg = function(p){
+
+ /* set color to svg element */
+ var svgXml = pJS.tmp.source_svg,
+ rgbHex = /#([0-9A-F]{3,6})/gi,
+ coloredSvgXml = svgXml.replace(rgbHex, function (m, r, g, b) {
+ if(p.color.rgb){
+ var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+p.opacity+')';
+ }else{
+ var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+p.opacity+')';
+ }
+ return color_value;
+ });
+
+ /* prepare to create img with colored svg */
+ var svg = new Blob([coloredSvgXml], {type: 'image/svg+xml;charset=utf-8'}),
+ DOMURL = window.URL || window.webkitURL || window,
+ url = DOMURL.createObjectURL(svg);
+
+ /* create particle img obj */
+ var img = new Image();
+ img.addEventListener('load', function(){
+ p.img.obj = img;
+ p.img.loaded = true;
+ DOMURL.revokeObjectURL(url);
+ pJS.tmp.count_svg++;
+ });
+ img.src = url;
+
+ };
+
+
+ pJS.fn.vendors.destroypJS = function(){
+ cancelAnimationFrame(pJS.fn.drawAnimFrame);
+ canvas_el.remove();
+ pJSDom = null;
+ };
+
+
+ pJS.fn.vendors.drawShape = function(c, startX, startY, sideLength, sideCountNumerator, sideCountDenominator){
+
+ // By Programming Thomas - https://programmingthomas.wordpress.com/2013/04/03/n-sided-shapes/
+ var sideCount = sideCountNumerator * sideCountDenominator;
+ var decimalSides = sideCountNumerator / sideCountDenominator;
+ var interiorAngleDegrees = (180 * (decimalSides - 2)) / decimalSides;
+ var interiorAngle = Math.PI - Math.PI * interiorAngleDegrees / 180; // convert to radians
+ c.save();
+ c.beginPath();
+ c.translate(startX, startY);
+ c.moveTo(0,0);
+ for (var i = 0; i < sideCount; i++) {
+ c.lineTo(sideLength,0);
+ c.translate(sideLength,0);
+ c.rotate(interiorAngle);
+ }
+ //c.stroke();
+ c.fill();
+ c.restore();
+
+ };
+
+ pJS.fn.vendors.exportImg = function(){
+ window.open(pJS.canvas.el.toDataURL('image/png'), '_blank');
+ };
+
+
+ pJS.fn.vendors.loadImg = function(type){
+
+ pJS.tmp.img_error = undefined;
+
+ if(pJS.particles.shape.image.src != ''){
+
+ if(type == 'svg'){
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', pJS.particles.shape.image.src);
+ xhr.onreadystatechange = function (data) {
+ if(xhr.readyState == 4){
+ if(xhr.status == 200){
+ pJS.tmp.source_svg = data.currentTarget.response;
+ pJS.fn.vendors.checkBeforeDraw();
+ }else{
+ console.log('Error pJS - Image not found');
+ pJS.tmp.img_error = true;
+ }
+ }
+ }
+ xhr.send();
+
+ }else{
+
+ var img = new Image();
+ img.addEventListener('load', function(){
+ pJS.tmp.img_obj = img;
+ pJS.fn.vendors.checkBeforeDraw();
+ });
+ img.src = pJS.particles.shape.image.src;
+
+ }
+
+ }else{
+ console.log('Error pJS - No image.src');
+ pJS.tmp.img_error = true;
+ }
+
+ };
+
+
+ pJS.fn.vendors.draw = function(){
+
+ if(pJS.particles.shape.type == 'image'){
+
+ if(pJS.tmp.img_type == 'svg'){
+
+ if(pJS.tmp.count_svg >= pJS.particles.number.value){
+ pJS.fn.particlesDraw();
+ if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+ else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+ }else{
+ //console.log('still loading...');
+ if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+ }
+
+ }else{
+
+ if(pJS.tmp.img_obj != undefined){
+ pJS.fn.particlesDraw();
+ if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+ else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+ }else{
+ if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+ }
+
+ }
+
+ }else{
+ pJS.fn.particlesDraw();
+ if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame);
+ else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw);
+ }
+
+ };
+
+
+ pJS.fn.vendors.checkBeforeDraw = function(){
+
+ // if shape is image
+ if(pJS.particles.shape.type == 'image'){
+
+ if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg == undefined){
+ pJS.tmp.checkAnimFrame = requestAnimFrame(check);
+ }else{
+ //console.log('images loaded! cancel check');
+ cancelRequestAnimFrame(pJS.tmp.checkAnimFrame);
+ if(!pJS.tmp.img_error){
+ pJS.fn.vendors.init();
+ pJS.fn.vendors.draw();
+ }
+
+ }
+
+ }else{
+ pJS.fn.vendors.init();
+ pJS.fn.vendors.draw();
+ }
+
+ };
+
+
+ pJS.fn.vendors.init = function(){
+
+ /* init canvas + particles */
+ pJS.fn.retinaInit();
+ pJS.fn.canvasInit();
+ pJS.fn.canvasSize();
+ pJS.fn.canvasPaint();
+ pJS.fn.particlesCreate();
+ pJS.fn.vendors.densityAutoParticles();
+
+ /* particles.line_linked - convert hex colors to rgb */
+ pJS.particles.line_linked.color_rgb_line = hexToRgb(pJS.particles.line_linked.color);
+
+ };
+
+
+ pJS.fn.vendors.start = function(){
+
+ if(isInArray('image', pJS.particles.shape.type)){
+ pJS.tmp.img_type = pJS.particles.shape.image.src.substr(pJS.particles.shape.image.src.length - 3);
+ pJS.fn.vendors.loadImg(pJS.tmp.img_type);
+ }else{
+ pJS.fn.vendors.checkBeforeDraw();
+ }
+
+ };
+
+
+
+
+ /* ---------- pJS - start ------------ */
+
+
+ pJS.fn.vendors.eventsListeners();
+
+ pJS.fn.vendors.start();
+
+
+
+};
+
+/* ---------- global functions - vendors ------------ */
+
+Object.deepExtend = function(destination, source) {
+ for (var property in source) {
+ if (source[property] && source[property].constructor &&
+ source[property].constructor === Object) {
+ destination[property] = destination[property] || {};
+ arguments.callee(destination[property], source[property]);
+ } else {
+ destination[property] = source[property];
+ }
+ }
+ return destination;
+};
+
+window.requestAnimFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback){
+ window.setTimeout(callback, 1000 / 60);
+ };
+})();
+
+window.cancelRequestAnimFrame = ( function() {
+ return window.cancelAnimationFrame ||
+ window.webkitCancelRequestAnimationFrame ||
+ window.mozCancelRequestAnimationFrame ||
+ window.oCancelRequestAnimationFrame ||
+ window.msCancelRequestAnimationFrame ||
+ clearTimeout
+} )();
+
+function hexToRgb(hex){
+ // By Tim Down - http://stackoverflow.com/a/5624139/3493650
+ // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
+ var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+ hex = hex.replace(shorthandRegex, function(m, r, g, b) {
+ return r + r + g + g + b + b;
+ });
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+ return result ? {
+ r: parseInt(result[1], 16),
+ g: parseInt(result[2], 16),
+ b: parseInt(result[3], 16)
+ } : null;
+};
+
+function clamp(number, min, max) {
+ return Math.min(Math.max(number, min), max);
+};
+
+function isInArray(value, array) {
+ return array.indexOf(value) > -1;
+}
+
+
+/* ---------- particles.js functions - start ------------ */
+
+window.pJSDom = [];
+
+window.particlesJS = function(tag_id, params){
+
+ //console.log(params);
+
+ /* no string id? so it's object params, and set the id with default id */
+ if(typeof(tag_id) != 'string'){
+ params = tag_id;
+ tag_id = 'particles-js';
+ }
+
+ /* no id? set the id to default id */
+ if(!tag_id){
+ tag_id = 'particles-js';
+ }
+
+ /* pJS elements */
+ var pJS_tag = document.getElementById(tag_id),
+ pJS_canvas_class = 'particles-js-canvas-el',
+ exist_canvas = pJS_tag.getElementsByClassName(pJS_canvas_class);
+
+ /* remove canvas if exists into the pJS target tag */
+ if(exist_canvas.length){
+ while(exist_canvas.length > 0){
+ pJS_tag.removeChild(exist_canvas[0]);
+ }
+ }
+
+ /* create canvas element */
+ var canvas_el = document.createElement('canvas');
+ canvas_el.className = pJS_canvas_class;
+
+ /* set size canvas */
+ canvas_el.style.width = "100%";
+ canvas_el.style.height = "100%";
+
+ /* append canvas */
+ var canvas = document.getElementById(tag_id).appendChild(canvas_el);
+
+ /* launch particle.js */
+ if(canvas != null){
+ pJSDom.push(new pJS(tag_id, params));
+ }
+
+};
+
+window.particlesJS.load = function(tag_id, path_config_json, callback){
+
+ /* load json config */
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', path_config_json);
+ xhr.onreadystatechange = function (data) {
+ if(xhr.readyState == 4){
+ if(xhr.status == 200){
+ var params = JSON.parse(data.currentTarget.response);
+ window.particlesJS(tag_id, params);
+ if(callback) callback();
+ }else{
+ console.log('Error pJS - XMLHttpRequest status: '+xhr.status);
+ console.log('Error pJS - File config not found');
+ }
+ }
+ };
+ xhr.send();
+
+};
\ No newline at end of file
diff --git a/public/assets/homepage/js/vendors/particles.js:Zone.Identifier b/public/assets/homepage/js/vendors/particles.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/particles.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/retina.min.js b/public/assets/homepage/js/vendors/retina.min.js
new file mode 100644
index 0000000..fb92b97
--- /dev/null
+++ b/public/assets/homepage/js/vendors/retina.min.js
@@ -0,0 +1,7 @@
+/*!
+ Retina
+ Version: 1.3.0
+ Plugin URL: http://imulus.github.io/retinajs/
+ License: Copyright 2014 Imulus, LLC | Released under the MIT license
+!*/
+!function(){function a(){}function b(a){return f.retinaImageSuffix+a}function c(a,c){if(this.path=a||"","undefined"!=typeof c&&null!==c)this.at_2x_path=c,this.perform_check=!1;else{if(void 0!==document.createElement){var d=document.createElement("a");d.href=this.path,d.pathname=d.pathname.replace(g,b),this.at_2x_path=d.href}else{var e=this.path.split("?");e[0]=e[0].replace(g,b),this.at_2x_path=e.join("?")}this.perform_check=!0}}function d(a){this.el=a,this.path=new c(this.el.getAttribute("src"),this.el.getAttribute("data-at2x"));var b=this;this.path.check_2x_variant(function(a){a&&b.swap()})}var e="undefined"==typeof exports?window:exports,f={retinaImageSuffix:"@2x",check_mime_type:!0,force_original_dimensions:!0};e.Retina=a,a.configure=function(a){null===a&&(a={});for(var b in a)a.hasOwnProperty(b)&&(f[b]=a[b])},a.init=function(a){null===a&&(a=e);var b=a.onload||function(){};a.onload=function(){var a,c,e=document.getElementsByTagName("img"),f=[];for(a=0;a1?!0:e.matchMedia&&e.matchMedia(a).matches?!0:!1};var g=/\.\w+$/;e.RetinaImagePath=c,c.confirmed_paths=[],c.prototype.is_external=function(){return!(!this.path.match(/^https?\:/i)||this.path.match("//"+document.domain))},c.prototype.check_2x_variant=function(a){var b,d=this;return this.is_external()?a(!1):this.perform_check||"undefined"==typeof this.at_2x_path||null===this.at_2x_path?this.at_2x_path in c.confirmed_paths?a(!0):(b=new XMLHttpRequest,b.open("HEAD",this.at_2x_path),b.onreadystatechange=function(){if(4!==b.readyState)return a(!1);if(b.status>=200&&b.status<=399){if(f.check_mime_type){var e=b.getResponseHeader("Content-Type");if(null===e||!e.match(/^image/i))return a(!1)}return c.confirmed_paths.push(d.at_2x_path),a(!0)}return a(!1)},b.send(),void 0):a(!0)},e.RetinaImage=d,d.prototype.swap=function(a){function b(){c.el.complete?(f.force_original_dimensions&&(c.el.setAttribute("width",c.el.offsetWidth),c.el.setAttribute("height",c.el.offsetHeight)),c.el.setAttribute("src",a)):setTimeout(b,5)}"undefined"==typeof a&&(a=this.path.at_2x_path);var c=this;b()},a.isRetina()&&a.init(e)}();
\ No newline at end of file
diff --git a/public/assets/homepage/js/vendors/retina.min.js:Zone.Identifier b/public/assets/homepage/js/vendors/retina.min.js:Zone.Identifier
new file mode 100644
index 0000000..212ab51
--- /dev/null
+++ b/public/assets/homepage/js/vendors/retina.min.js:Zone.Identifier
@@ -0,0 +1,3 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=C:\Users\dev perusahaan pst\Downloads\crafto.zip
diff --git a/public/assets/homepage/js/vendors/skrollr.js b/public/assets/homepage/js/vendors/skrollr.js
new file mode 100644
index 0000000..5585921
--- /dev/null
+++ b/public/assets/homepage/js/vendors/skrollr.js
@@ -0,0 +1,1779 @@
+/*!
+ Skrollr
+ Plugin URL: https://github.com/Prinzhorn/skrollr
+ License: Copyright Alexander Prinzhorn | Free to use under terms of MIT license
+!*/
+
+(function(window, document, undefined) {
+ 'use strict';
+
+ /*
+ * Global api.
+ */
+ var skrollr = {
+ get: function() {
+ return _instance;
+ },
+ //Main entry point.
+ init: function(options) {
+ return _instance || new Skrollr(options);
+ },
+ VERSION: '0.6.30'
+ };
+
+ //Minify optimization.
+ var hasProp = Object.prototype.hasOwnProperty;
+ var Math = window.Math;
+ var getStyle = window.getComputedStyle;
+
+ //They will be filled when skrollr gets initialized.
+ var documentElement;
+ var body;
+
+ var EVENT_TOUCHSTART = 'touchstart';
+ var EVENT_TOUCHMOVE = 'touchmove';
+ var EVENT_TOUCHCANCEL = 'touchcancel';
+ var EVENT_TOUCHEND = 'touchend';
+
+ var SKROLLABLE_CLASS = 'skrollable';
+ var SKROLLABLE_BEFORE_CLASS = SKROLLABLE_CLASS + '-before';
+ var SKROLLABLE_BETWEEN_CLASS = SKROLLABLE_CLASS + '-between';
+ var SKROLLABLE_AFTER_CLASS = SKROLLABLE_CLASS + '-after';
+
+ var SKROLLR_CLASS = 'skrollr';
+ var NO_SKROLLR_CLASS = 'no-' + SKROLLR_CLASS;
+ var SKROLLR_DESKTOP_CLASS = SKROLLR_CLASS + '-desktop';
+ var SKROLLR_MOBILE_CLASS = SKROLLR_CLASS + '-mobile';
+
+ var DEFAULT_EASING = 'linear';
+ var DEFAULT_DURATION = 1000;//ms
+ var DEFAULT_MOBILE_DECELERATION = 0.004;//pixel/ms²
+
+ var DEFAULT_SKROLLRBODY = 'skrollr-body';
+
+ var DEFAULT_SMOOTH_SCROLLING_DURATION = 200;//ms
+
+ var ANCHOR_START = 'start';
+ var ANCHOR_END = 'end';
+ var ANCHOR_CENTER = 'center';
+ var ANCHOR_BOTTOM = 'bottom';
+
+ //The property which will be added to the DOM element to hold the ID of the skrollable.
+ var SKROLLABLE_ID_DOM_PROPERTY = '___skrollable_id';
+
+ var rxTouchIgnoreTags = /^(?:input|textarea|button|select)$/i;
+
+ var rxTrim = /^\s+|\s+$/g;
+
+ //Find all data-attributes. data-[_constant]-[offset]-[anchor]-[anchor].
+ var rxKeyframeAttribute = /^data(?:-(_\w+))?(?:-?(-?\d*\.?\d+p?))?(?:-?(start|end|top|center|bottom))?(?:-?(top|center|bottom))?$/;
+
+ var rxPropValue = /\s*(@?[\w\-\[\]]+)\s*:\s*(.+?)\s*(?:;|$)/gi;
+
+ //Easing function names follow the property in square brackets.
+ var rxPropEasing = /^(@?[a-z\-]+)\[(\w+)\]$/;
+
+ var rxCamelCase = /-([a-z0-9_])/g;
+ var rxCamelCaseFn = function(str, letter) {
+ return letter.toUpperCase();
+ };
+
+ //Numeric values with optional sign.
+ var rxNumericValue = /[\-+]?[\d]*\.?[\d]+/g;
+
+ //Used to replace occurences of {?} with a number.
+ var rxInterpolateString = /\{\?\}/g;
+
+ //Finds rgb(a) colors, which don't use the percentage notation.
+ var rxRGBAIntegerColor = /rgba?\(\s*-?\d+\s*,\s*-?\d+\s*,\s*-?\d+/g;
+
+ //Finds all gradients.
+ var rxGradient = /[a-z\-]+-gradient/g;
+
+ //Vendor prefix. Will be set once skrollr gets initialized.
+ var theCSSPrefix = '';
+ var theDashedCSSPrefix = '';
+
+ //Will be called once (when skrollr gets initialized).
+ var detectCSSPrefix = function() {
+ //Only relevant prefixes. May be extended.
+ //Could be dangerous if there will ever be a CSS property which actually starts with "ms". Don't hope so.
+ var rxPrefixes = /^(?:O|Moz|webkit|ms)|(?:-(?:o|moz|webkit|ms)-)/;
+
+ //Detect prefix for current browser by finding the first property using a prefix.
+ if(!getStyle) {
+ return;
+ }
+
+ var style = getStyle(body, null);
+
+ for(var k in style) {
+ //We check the key and if the key is a number, we check the value as well, because safari's getComputedStyle returns some weird array-like thingy.
+ theCSSPrefix = (k.match(rxPrefixes) || (+k == k && style[k].match(rxPrefixes)));
+
+ if(theCSSPrefix) {
+ break;
+ }
+ }
+
+ //Did we even detect a prefix?
+ if(!theCSSPrefix) {
+ theCSSPrefix = theDashedCSSPrefix = '';
+
+ return;
+ }
+
+ theCSSPrefix = theCSSPrefix[0];
+
+ //We could have detected either a dashed prefix or this camelCaseish-inconsistent stuff.
+ if(theCSSPrefix.slice(0,1) === '-') {
+ theDashedCSSPrefix = theCSSPrefix;
+
+ //There's no logic behind these. Need a look up.
+ theCSSPrefix = ({
+ '-webkit-': 'webkit',
+ '-moz-': 'Moz',
+ '-ms-': 'ms',
+ '-o-': 'O'
+ })[theCSSPrefix];
+ } else {
+ theDashedCSSPrefix = '-' + theCSSPrefix.toLowerCase() + '-';
+ }
+ };
+
+ var polyfillRAF = function() {
+ var requestAnimFrame = window.requestAnimationFrame || window[theCSSPrefix.toLowerCase() + 'RequestAnimationFrame'];
+
+ var lastTime = _now();
+
+ if(_isMobile || !requestAnimFrame) {
+ requestAnimFrame = function(callback) {
+ //How long did it take to render?
+ var deltaTime = _now() - lastTime;
+ var delay = Math.max(0, 1000 / 60 - deltaTime);
+
+ return window.setTimeout(function() {
+ lastTime = _now();
+ callback();
+ }, delay);
+ };
+ }
+
+ return requestAnimFrame;
+ };
+
+ var polyfillCAF = function() {
+ var cancelAnimFrame = window.cancelAnimationFrame || window[theCSSPrefix.toLowerCase() + 'CancelAnimationFrame'];
+
+ if(_isMobile || !cancelAnimFrame) {
+ cancelAnimFrame = function(timeout) {
+ return window.clearTimeout(timeout);
+ };
+ }
+
+ return cancelAnimFrame;
+ };
+
+ //Built-in easing functions.
+ var easings = {
+ begin: function() {
+ return 0;
+ },
+ end: function() {
+ return 1;
+ },
+ linear: function(p) {
+ return p;
+ },
+ quadratic: function(p) {
+ return p * p;
+ },
+ cubic: function(p) {
+ return p * p * p;
+ },
+ swing: function(p) {
+ return (-Math.cos(p * Math.PI) / 2) + 0.5;
+ },
+ sqrt: function(p) {
+ return Math.sqrt(p);
+ },
+ outCubic: function(p) {
+ return (Math.pow((p - 1), 3) + 1);
+ },
+ //see https://www.desmos.com/calculator/tbr20s8vd2 for how I did this
+ bounce: function(p) {
+ var a;
+
+ if(p <= 0.5083) {
+ a = 3;
+ } else if(p <= 0.8489) {
+ a = 9;
+ } else if(p <= 0.96208) {
+ a = 27;
+ } else if(p <= 0.99981) {
+ a = 91;
+ } else {
+ return 1;
+ }
+
+ return 1 - Math.abs(3 * Math.cos(p * a * 1.028) / a);
+ }
+ };
+
+ /**
+ * Constructor.
+ */
+ function Skrollr(options) {
+ documentElement = document.documentElement;
+ body = document.body;
+
+ detectCSSPrefix();
+
+ _instance = this;
+
+ options = options || {};
+
+ _constants = options.constants || {};
+
+ //We allow defining custom easings or overwrite existing.
+ if(options.easing) {
+ for(var e in options.easing) {
+ easings[e] = options.easing[e];
+ }
+ }
+
+ _edgeStrategy = options.edgeStrategy || 'set';
+
+ _listeners = {
+ //Function to be called right before rendering.
+ beforerender: options.beforerender,
+
+ //Function to be called right after finishing rendering.
+ render: options.render,
+
+ //Function to be called whenever an element with the `data-emit-events` attribute passes a keyframe.
+ keyframe: options.keyframe
+ };
+
+ //forceHeight is true by default
+ _forceHeight = options.forceHeight !== false;
+
+ if(_forceHeight) {
+ _scale = options.scale || 1;
+ }
+
+ _mobileDeceleration = options.mobileDeceleration || DEFAULT_MOBILE_DECELERATION;
+
+ _smoothScrollingEnabled = options.smoothScrolling !== false;
+ _smoothScrollingDuration = options.smoothScrollingDuration || DEFAULT_SMOOTH_SCROLLING_DURATION;
+
+ //Dummy object. Will be overwritten in the _render method when smooth scrolling is calculated.
+ _smoothScrolling = {
+ targetTop: _instance.getScrollTop()
+ };
+
+ //A custom check function may be passed.
+ _isMobile = ((options.mobileCheck || function() {
+ return (/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera);
+ })());
+
+ if(_isMobile) {
+ _skrollrBody = document.getElementById(options.skrollrBody || DEFAULT_SKROLLRBODY);
+
+ //Detect 3d transform if there's a skrollr-body (only needed for #skrollr-body).
+ if(_skrollrBody) {
+ _detect3DTransforms();
+ }
+
+ _initMobile();
+ _updateClass(documentElement, [SKROLLR_CLASS, SKROLLR_MOBILE_CLASS], [NO_SKROLLR_CLASS]);
+ } else {
+ _updateClass(documentElement, [SKROLLR_CLASS, SKROLLR_DESKTOP_CLASS], [NO_SKROLLR_CLASS]);
+ }
+
+ //Triggers parsing of elements and a first reflow.
+ _instance.refresh();
+
+ _addEvent(window, 'resize orientationchange', function() {
+ var width = documentElement.clientWidth;
+ var height = documentElement.clientHeight;
+
+ //Only reflow if the size actually changed (#271).
+ if(height !== _lastViewportHeight || width !== _lastViewportWidth) {
+ _lastViewportHeight = height;
+ _lastViewportWidth = width;
+
+ _requestReflow = true;
+ }
+ });
+
+ var requestAnimFrame = polyfillRAF();
+
+ //Let's go.
+ (function animloop(){
+ _render();
+ _animFrame = requestAnimFrame(animloop);
+ }());
+
+ return _instance;
+ }
+
+ /**
+ * (Re)parses some or all elements.
+ */
+ Skrollr.prototype.refresh = function(elements) {
+ var elementIndex;
+ var elementsLength;
+ var ignoreID = false;
+
+ //Completely reparse anything without argument.
+ if(elements === undefined) {
+ //Ignore that some elements may already have a skrollable ID.
+ ignoreID = true;
+
+ _skrollables = [];
+ _skrollableIdCounter = 0;
+
+ elements = document.getElementsByTagName('*');
+ } else if(elements.length === undefined) {
+ //We also accept a single element as parameter.
+ elements = [elements];
+ }
+
+ elementIndex = 0;
+ elementsLength = elements.length;
+
+ for(; elementIndex < elementsLength; elementIndex++) {
+ var el = elements[elementIndex];
+ var anchorTarget = el;
+ var keyFrames = [];
+
+ //If this particular element should be smooth scrolled.
+ var smoothScrollThis = _smoothScrollingEnabled;
+
+ //The edge strategy for this particular element.
+ var edgeStrategy = _edgeStrategy;
+
+ //If this particular element should emit keyframe events.
+ var emitEvents = false;
+
+ //If we're reseting the counter, remove any old element ids that may be hanging around.
+ if(ignoreID && SKROLLABLE_ID_DOM_PROPERTY in el) {
+ delete el[SKROLLABLE_ID_DOM_PROPERTY];
+ }
+
+ if(!el.attributes) {
+ continue;
+ }
+
+ //Iterate over all attributes and search for key frame attributes.
+ var attributeIndex = 0;
+ var attributesLength = el.attributes.length;
+
+ for (; attributeIndex < attributesLength; attributeIndex++) {
+ var attr = el.attributes[attributeIndex];
+
+ if(attr.name === 'data-anchor-target') {
+ anchorTarget = document.querySelector(attr.value);
+
+ if(anchorTarget === null) {
+ throw 'Unable to find anchor target "' + attr.value + '"';
+ }
+
+ continue;
+ }
+
+ //Global smooth scrolling can be overridden by the element attribute.
+ if(attr.name === 'data-smooth-scrolling') {
+ smoothScrollThis = attr.value !== 'off';
+
+ continue;
+ }
+
+ //Global edge strategy can be overridden by the element attribute.
+ if(attr.name === 'data-edge-strategy') {
+ edgeStrategy = attr.value;
+
+ continue;
+ }
+
+ //Is this element tagged with the `data-emit-events` attribute?
+ if(attr.name === 'data-emit-events') {
+ emitEvents = true;
+
+ continue;
+ }
+
+ var match = attr.name.match(rxKeyframeAttribute);
+
+ if(match === null) {
+ continue;
+ }
+
+ var kf = {
+ props: attr.value,
+ //Point back to the element as well.
+ element: el,
+ //The name of the event which this keyframe will fire, if emitEvents is
+ eventType: attr.name.replace(rxCamelCase, rxCamelCaseFn)
+ };
+
+ keyFrames.push(kf);
+
+ var constant = match[1];
+
+ if(constant) {
+ //Strip the underscore prefix.
+ kf.constant = constant.substr(1);
+ }
+
+ //Get the key frame offset.
+ var offset = match[2];
+
+ //Is it a percentage offset?
+ if(/p$/.test(offset)) {
+ kf.isPercentage = true;
+ kf.offset = (offset.slice(0, -1) | 0) / 100;
+ } else {
+ kf.offset = (offset | 0);
+ }
+
+ var anchor1 = match[3];
+
+ //If second anchor is not set, the first will be taken for both.
+ var anchor2 = match[4] || anchor1;
+
+ //"absolute" (or "classic") mode, where numbers mean absolute scroll offset.
+ if(!anchor1 || anchor1 === ANCHOR_START || anchor1 === ANCHOR_END) {
+ kf.mode = 'absolute';
+
+ //data-end needs to be calculated after all key frames are known.
+ if(anchor1 === ANCHOR_END) {
+ kf.isEnd = true;
+ } else if(!kf.isPercentage) {
+ //For data-start we can already set the key frame w/o calculations.
+ //#59: "scale" options should only affect absolute mode.
+ kf.offset = kf.offset * _scale;
+ }
+ }
+ //"relative" mode, where numbers are relative to anchors.
+ else {
+ kf.mode = 'relative';
+ kf.anchors = [anchor1, anchor2];
+ }
+ }
+
+ //Does this element have key frames?
+ if(!keyFrames.length) {
+ continue;
+ }
+
+ //Will hold the original style and class attributes before we controlled the element (see #80).
+ var styleAttr, classAttr;
+
+ var id;
+
+ if(!ignoreID && SKROLLABLE_ID_DOM_PROPERTY in el) {
+ //We already have this element under control. Grab the corresponding skrollable id.
+ id = el[SKROLLABLE_ID_DOM_PROPERTY];
+ styleAttr = _skrollables[id].styleAttr;
+ classAttr = _skrollables[id].classAttr;
+ } else {
+ //It's an unknown element. Asign it a new skrollable id.
+ id = (el[SKROLLABLE_ID_DOM_PROPERTY] = _skrollableIdCounter++);
+ styleAttr = el.style.cssText;
+ classAttr = _getClass(el);
+ }
+
+ _skrollables[id] = {
+ element: el,
+ styleAttr: styleAttr,
+ classAttr: classAttr,
+ anchorTarget: anchorTarget,
+ keyFrames: keyFrames,
+ smoothScrolling: smoothScrollThis,
+ edgeStrategy: edgeStrategy,
+ emitEvents: emitEvents,
+ lastFrameIndex: -1
+ };
+
+ _updateClass(el, [SKROLLABLE_CLASS], []);
+ }
+
+ //Reflow for the first time.
+ _reflow();
+
+ //Now that we got all key frame numbers right, actually parse the properties.
+ elementIndex = 0;
+ elementsLength = elements.length;
+
+ for(; elementIndex < elementsLength; elementIndex++) {
+ var sk = _skrollables[elements[elementIndex][SKROLLABLE_ID_DOM_PROPERTY]];
+
+ if(sk === undefined) {
+ continue;
+ }
+
+ //Parse the property string to objects
+ _parseProps(sk);
+
+ //Fill key frames with missing properties from left and right
+ _fillProps(sk);
+ }
+
+ return _instance;
+ };
+
+ /**
+ * Transform "relative" mode to "absolute" mode.
+ * That is, calculate anchor position and offset of element.
+ */
+ Skrollr.prototype.relativeToAbsolute = function(element, viewportAnchor, elementAnchor) {
+ var viewportHeight = documentElement.clientHeight;
+ var box = element.getBoundingClientRect();
+ var absolute = box.top;
+
+ //#100: IE doesn't supply "height" with getBoundingClientRect.
+ var boxHeight = box.bottom - box.top;
+
+ if(viewportAnchor === ANCHOR_BOTTOM) {
+ absolute -= viewportHeight;
+ } else if(viewportAnchor === ANCHOR_CENTER) {
+ absolute -= viewportHeight / 2;
+ }
+
+ if(elementAnchor === ANCHOR_BOTTOM) {
+ absolute += boxHeight;
+ } else if(elementAnchor === ANCHOR_CENTER) {
+ absolute += boxHeight / 2;
+ }
+
+ //Compensate scrolling since getBoundingClientRect is relative to viewport.
+ absolute += _instance.getScrollTop();
+
+ return (absolute + 0.5) | 0;
+ };
+
+ /**
+ * Animates scroll top to new position.
+ */
+ Skrollr.prototype.animateTo = function(top, options) {
+ options = options || {};
+
+ var now = _now();
+ var scrollTop = _instance.getScrollTop();
+ var duration = options.duration === undefined ? DEFAULT_DURATION : options.duration;
+
+ //Setting this to a new value will automatically cause the current animation to stop, if any.
+ _scrollAnimation = {
+ startTop: scrollTop,
+ topDiff: top - scrollTop,
+ targetTop: top,
+ duration: duration,
+ startTime: now,
+ endTime: now + duration,
+ easing: easings[options.easing || DEFAULT_EASING],
+ done: options.done
+ };
+
+ //Don't queue the animation if there's nothing to animate.
+ if(!_scrollAnimation.topDiff) {
+ if(_scrollAnimation.done) {
+ _scrollAnimation.done.call(_instance, false);
+ }
+
+ _scrollAnimation = undefined;
+ }
+
+ return _instance;
+ };
+
+ /**
+ * Stops animateTo animation.
+ */
+ Skrollr.prototype.stopAnimateTo = function() {
+ if(_scrollAnimation && _scrollAnimation.done) {
+ _scrollAnimation.done.call(_instance, true);
+ }
+
+ _scrollAnimation = undefined;
+ };
+
+ /**
+ * Returns if an animation caused by animateTo is currently running.
+ */
+ Skrollr.prototype.isAnimatingTo = function() {
+ return !!_scrollAnimation;
+ };
+
+ Skrollr.prototype.isMobile = function() {
+ return _isMobile;
+ };
+
+ Skrollr.prototype.setScrollTop = function(top, force) {
+ _forceRender = (force === true);
+
+ if(_isMobile) {
+ _mobileOffset = Math.min(Math.max(top, 0), _maxKeyFrame);
+ } else {
+ window.scrollTo(0, top);
+ }
+
+ return _instance;
+ };
+
+ Skrollr.prototype.getScrollTop = function() {
+ if(_isMobile) {
+ return _mobileOffset;
+ } else {
+ return window.pageYOffset || documentElement.scrollTop || body.scrollTop || 0;
+ }
+ };
+
+ Skrollr.prototype.getMaxScrollTop = function() {
+ return _maxKeyFrame;
+ };
+
+ Skrollr.prototype.on = function(name, fn) {
+ _listeners[name] = fn;
+
+ return _instance;
+ };
+
+ Skrollr.prototype.off = function(name) {
+ delete _listeners[name];
+
+ return _instance;
+ };
+
+ Skrollr.prototype.destroy = function() {
+ var cancelAnimFrame = polyfillCAF();
+ cancelAnimFrame(_animFrame);
+ _removeAllEvents();
+
+ _updateClass(documentElement, [NO_SKROLLR_CLASS], [SKROLLR_CLASS, SKROLLR_DESKTOP_CLASS, SKROLLR_MOBILE_CLASS]);
+
+ var skrollableIndex = 0;
+ var skrollablesLength = _skrollables.length;
+
+ for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
+ _reset(_skrollables[skrollableIndex].element);
+ }
+
+ documentElement.style.overflow = body.style.overflow = '';
+ documentElement.style.height = body.style.height = '';
+
+ if(_skrollrBody) {
+ skrollr.setStyle(_skrollrBody, 'transform', 'none');
+ }
+
+ _instance = undefined;
+ _skrollrBody = undefined;
+ _listeners = undefined;
+ _forceHeight = undefined;
+ _maxKeyFrame = 0;
+ _scale = 1;
+ _constants = undefined;
+ _mobileDeceleration = undefined;
+ _direction = 'down';
+ _lastTop = -1;
+ _lastViewportWidth = 0;
+ _lastViewportHeight = 0;
+ _requestReflow = false;
+ _scrollAnimation = undefined;
+ _smoothScrollingEnabled = undefined;
+ _smoothScrollingDuration = undefined;
+ _smoothScrolling = undefined;
+ _forceRender = undefined;
+ _skrollableIdCounter = 0;
+ _edgeStrategy = undefined;
+ _isMobile = false;
+ _mobileOffset = 0;
+ _translateZ = undefined;
+ };
+
+ /*
+ Private methods.
+ */
+
+ var _initMobile = function() {
+ var initialElement;
+ var initialTouchY;
+ var initialTouchX;
+ var currentElement;
+ var currentTouchY;
+ var currentTouchX;
+ var lastTouchY;
+ var deltaY;
+
+ var initialTouchTime;
+ var currentTouchTime;
+ var lastTouchTime;
+ var deltaTime;
+
+ _addEvent(documentElement, [EVENT_TOUCHSTART, EVENT_TOUCHMOVE, EVENT_TOUCHCANCEL, EVENT_TOUCHEND].join(' '), function(e) {
+ var touch = e.changedTouches[0];
+
+ currentElement = e.target;
+
+ //We don't want text nodes.
+ while(currentElement.nodeType === 3) {
+ currentElement = currentElement.parentNode;
+ }
+
+ currentTouchY = touch.clientY;
+ currentTouchX = touch.clientX;
+ currentTouchTime = e.timeStamp;
+
+ if(!rxTouchIgnoreTags.test(currentElement.tagName)) {
+ e.preventDefault();
+ }
+
+ switch(e.type) {
+ case EVENT_TOUCHSTART:
+ //The last element we tapped on.
+ if(initialElement) {
+ initialElement.blur();
+ }
+
+ _instance.stopAnimateTo();
+
+ initialElement = currentElement;
+
+ initialTouchY = lastTouchY = currentTouchY;
+ initialTouchX = currentTouchX;
+ initialTouchTime = currentTouchTime;
+
+ break;
+ case EVENT_TOUCHMOVE:
+ //Prevent default event on touchIgnore elements in case they don't have focus yet.
+ if(rxTouchIgnoreTags.test(currentElement.tagName) && document.activeElement !== currentElement) {
+ e.preventDefault();
+ }
+
+ deltaY = currentTouchY - lastTouchY;
+ deltaTime = currentTouchTime - lastTouchTime;
+
+ _instance.setScrollTop(_mobileOffset - deltaY, true);
+
+ lastTouchY = currentTouchY;
+ lastTouchTime = currentTouchTime;
+ break;
+ default:
+ case EVENT_TOUCHCANCEL:
+ case EVENT_TOUCHEND:
+ var distanceY = initialTouchY - currentTouchY;
+ var distanceX = initialTouchX - currentTouchX;
+ var distance2 = distanceX * distanceX + distanceY * distanceY;
+
+ //Check if it was more like a tap (moved less than 7px).
+ if(distance2 < 49) {
+ if(!rxTouchIgnoreTags.test(initialElement.tagName)) {
+ initialElement.focus();
+
+ //It was a tap, click the element.
+ var clickEvent = document.createEvent('MouseEvents');
+ clickEvent.initMouseEvent('click', true, true, e.view, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, 0, null);
+ initialElement.dispatchEvent(clickEvent);
+ }
+
+ return;
+ }
+
+ initialElement = undefined;
+
+ var speed = deltaY / deltaTime;
+
+ //Cap speed at 3 pixel/ms.
+ speed = Math.max(Math.min(speed, 3), -3);
+
+ var duration = Math.abs(speed / _mobileDeceleration);
+ var targetOffset = speed * duration + 0.5 * _mobileDeceleration * duration * duration;
+ var targetTop = _instance.getScrollTop() - targetOffset;
+
+ //Relative duration change for when scrolling above bounds.
+ var targetRatio = 0;
+
+ //Change duration proportionally when scrolling would leave bounds.
+ if(targetTop > _maxKeyFrame) {
+ targetRatio = (_maxKeyFrame - targetTop) / targetOffset;
+
+ targetTop = _maxKeyFrame;
+ } else if(targetTop < 0) {
+ targetRatio = -targetTop / targetOffset;
+
+ targetTop = 0;
+ }
+
+ duration = duration * (1 - targetRatio);
+
+ _instance.animateTo((targetTop + 0.5) | 0, {easing: 'outCubic', duration: duration});
+ break;
+ }
+ });
+
+ //Just in case there has already been some native scrolling, reset it.
+ window.scrollTo(0, 0);
+ documentElement.style.overflow = body.style.overflow = 'hidden';
+ };
+
+ /**
+ * Updates key frames which depend on others / need to be updated on resize.
+ * That is "end" in "absolute" mode and all key frames in "relative" mode.
+ * Also handles constants, because they may change on resize.
+ */
+ var _updateDependentKeyFrames = function() {
+ var viewportHeight = documentElement.clientHeight;
+ var processedConstants = _processConstants();
+ var skrollable;
+ var element;
+ var anchorTarget;
+ var keyFrames;
+ var keyFrameIndex;
+ var keyFramesLength;
+ var kf;
+ var skrollableIndex;
+ var skrollablesLength;
+ var offset;
+ var constantValue;
+
+ //First process all relative-mode elements and find the max key frame.
+ skrollableIndex = 0;
+ skrollablesLength = _skrollables.length;
+
+ for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
+ skrollable = _skrollables[skrollableIndex];
+ element = skrollable.element;
+ anchorTarget = skrollable.anchorTarget;
+ keyFrames = skrollable.keyFrames;
+
+ keyFrameIndex = 0;
+ keyFramesLength = keyFrames.length;
+
+ for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
+ kf = keyFrames[keyFrameIndex];
+
+ offset = kf.offset;
+ constantValue = processedConstants[kf.constant] || 0;
+
+ kf.frame = offset;
+
+ if(kf.isPercentage) {
+ //Convert the offset to percentage of the viewport height.
+ offset = offset * viewportHeight;
+
+ //Absolute + percentage mode.
+ kf.frame = offset;
+ }
+
+ if(kf.mode === 'relative') {
+ _reset(element);
+
+ kf.frame = _instance.relativeToAbsolute(anchorTarget, kf.anchors[0], kf.anchors[1]) - offset;
+
+ _reset(element, true);
+ }
+
+ kf.frame += constantValue;
+
+ //Only search for max key frame when forceHeight is enabled.
+ if(_forceHeight) {
+ //Find the max key frame, but don't use one of the data-end ones for comparison.
+ if(!kf.isEnd && kf.frame > _maxKeyFrame) {
+ _maxKeyFrame = kf.frame;
+ }
+ }
+ }
+ }
+
+ //#133: The document can be larger than the maxKeyFrame we found.
+ _maxKeyFrame = Math.max(_maxKeyFrame, _getDocumentHeight());
+
+ //Now process all data-end keyframes.
+ skrollableIndex = 0;
+ skrollablesLength = _skrollables.length;
+
+ for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
+ skrollable = _skrollables[skrollableIndex];
+ keyFrames = skrollable.keyFrames;
+
+ keyFrameIndex = 0;
+ keyFramesLength = keyFrames.length;
+
+ for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
+ kf = keyFrames[keyFrameIndex];
+
+ constantValue = processedConstants[kf.constant] || 0;
+
+ if(kf.isEnd) {
+ kf.frame = _maxKeyFrame - kf.offset + constantValue;
+ }
+ }
+
+ skrollable.keyFrames.sort(_keyFrameComparator);
+ }
+ };
+
+ /**
+ * Calculates and sets the style properties for the element at the given frame.
+ * @param fakeFrame The frame to render at when smooth scrolling is enabled.
+ * @param actualFrame The actual frame we are at.
+ */
+ var _calcSteps = function(fakeFrame, actualFrame) {
+ //Iterate over all skrollables.
+ var skrollableIndex = 0;
+ var skrollablesLength = _skrollables.length;
+
+ for(; skrollableIndex < skrollablesLength; skrollableIndex++) {
+ var skrollable = _skrollables[skrollableIndex];
+ var element = skrollable.element;
+ var frame = skrollable.smoothScrolling ? fakeFrame : actualFrame;
+ var frames = skrollable.keyFrames;
+ var framesLength = frames.length;
+ var firstFrame = frames[0];
+ var lastFrame = frames[frames.length - 1];
+ var beforeFirst = frame < firstFrame.frame;
+ var afterLast = frame > lastFrame.frame;
+ var firstOrLastFrame = beforeFirst ? firstFrame : lastFrame;
+ var emitEvents = skrollable.emitEvents;
+ var lastFrameIndex = skrollable.lastFrameIndex;
+ var key;
+ var value;
+
+ //If we are before/after the first/last frame, set the styles according to the given edge strategy.
+ if(beforeFirst || afterLast) {
+ //Check if we already handled this edge case last time.
+ //Note: using setScrollTop it's possible that we jumped from one edge to the other.
+ if(beforeFirst && skrollable.edge === -1 || afterLast && skrollable.edge === 1) {
+ continue;
+ }
+
+ //Add the skrollr-before or -after class.
+ if(beforeFirst) {
+ _updateClass(element, [SKROLLABLE_BEFORE_CLASS], [SKROLLABLE_AFTER_CLASS, SKROLLABLE_BETWEEN_CLASS]);
+
+ //This handles the special case where we exit the first keyframe.
+ if(emitEvents && lastFrameIndex > -1) {
+ _emitEvent(element, firstFrame.eventType, _direction);
+ skrollable.lastFrameIndex = -1;
+ }
+ } else {
+ _updateClass(element, [SKROLLABLE_AFTER_CLASS], [SKROLLABLE_BEFORE_CLASS, SKROLLABLE_BETWEEN_CLASS]);
+
+ //This handles the special case where we exit the last keyframe.
+ if(emitEvents && lastFrameIndex < framesLength) {
+ _emitEvent(element, lastFrame.eventType, _direction);
+ skrollable.lastFrameIndex = framesLength;
+ }
+ }
+
+ //Remember that we handled the edge case (before/after the first/last keyframe).
+ skrollable.edge = beforeFirst ? -1 : 1;
+
+ switch(skrollable.edgeStrategy) {
+ case 'reset':
+ _reset(element);
+ continue;
+ case 'ease':
+ //Handle this case like it would be exactly at first/last keyframe and just pass it on.
+ frame = firstOrLastFrame.frame;
+ break;
+ default:
+ case 'set':
+ var props = firstOrLastFrame.props;
+
+ for(key in props) {
+ if(hasProp.call(props, key)) {
+ value = _interpolateString(props[key].value);
+
+ //Set style or attribute.
+ if(key.indexOf('@') === 0) {
+ element.setAttribute(key.substr(1), value);
+ } else {
+ skrollr.setStyle(element, key, value);
+ }
+ }
+ }
+
+ continue;
+ }
+ } else {
+ //Did we handle an edge last time?
+ if(skrollable.edge !== 0) {
+ _updateClass(element, [SKROLLABLE_CLASS, SKROLLABLE_BETWEEN_CLASS], [SKROLLABLE_BEFORE_CLASS, SKROLLABLE_AFTER_CLASS]);
+ skrollable.edge = 0;
+ }
+ }
+
+ //Find out between which two key frames we are right now.
+ var keyFrameIndex = 0;
+
+ for(; keyFrameIndex < framesLength - 1; keyFrameIndex++) {
+ if(frame >= frames[keyFrameIndex].frame && frame <= frames[keyFrameIndex + 1].frame) {
+ var left = frames[keyFrameIndex];
+ var right = frames[keyFrameIndex + 1];
+
+ for(key in left.props) {
+ if(hasProp.call(left.props, key)) {
+ var progress = (frame - left.frame) / (right.frame - left.frame);
+
+ //Transform the current progress using the given easing function.
+ progress = left.props[key].easing(progress);
+
+ //Interpolate between the two values
+ value = _calcInterpolation(left.props[key].value, right.props[key].value, progress);
+
+ value = _interpolateString(value);
+
+ //Set style or attribute.
+ if(key.indexOf('@') === 0) {
+ element.setAttribute(key.substr(1), value);
+ } else {
+ skrollr.setStyle(element, key, value);
+ }
+ }
+ }
+
+ //Are events enabled on this element?
+ //This code handles the usual cases of scrolling through different keyframes.
+ //The special cases of before first and after last keyframe are handled above.
+ if(emitEvents) {
+ //Did we pass a new keyframe?
+ if(lastFrameIndex !== keyFrameIndex) {
+ if(_direction === 'down') {
+ _emitEvent(element, left.eventType, _direction);
+ } else {
+ _emitEvent(element, right.eventType, _direction);
+ }
+
+ skrollable.lastFrameIndex = keyFrameIndex;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ };
+
+ /**
+ * Renders all elements.
+ */
+ var _render = function() {
+ if(_requestReflow) {
+ _requestReflow = false;
+ _reflow();
+ }
+
+ //We may render something else than the actual scrollbar position.
+ var renderTop = _instance.getScrollTop();
+
+ //If there's an animation, which ends in current render call, call the callback after rendering.
+ var afterAnimationCallback;
+ var now = _now();
+ var progress;
+
+ //Before actually rendering handle the scroll animation, if any.
+ if(_scrollAnimation) {
+ //It's over
+ if(now >= _scrollAnimation.endTime) {
+ renderTop = _scrollAnimation.targetTop;
+ afterAnimationCallback = _scrollAnimation.done;
+ _scrollAnimation = undefined;
+ } else {
+ //Map the current progress to the new progress using given easing function.
+ progress = _scrollAnimation.easing((now - _scrollAnimation.startTime) / _scrollAnimation.duration);
+
+ renderTop = (_scrollAnimation.startTop + progress * _scrollAnimation.topDiff) | 0;
+ }
+
+ _instance.setScrollTop(renderTop, true);
+ }
+ //Smooth scrolling only if there's no animation running and if we're not forcing the rendering.
+ else if(!_forceRender) {
+ var smoothScrollingDiff = _smoothScrolling.targetTop - renderTop;
+
+ //The user scrolled, start new smooth scrolling.
+ if(smoothScrollingDiff) {
+ _smoothScrolling = {
+ startTop: _lastTop,
+ topDiff: renderTop - _lastTop,
+ targetTop: renderTop,
+ startTime: _lastRenderCall,
+ endTime: _lastRenderCall + _smoothScrollingDuration
+ };
+ }
+
+ //Interpolate the internal scroll position (not the actual scrollbar).
+ if(now <= _smoothScrolling.endTime) {
+ //Map the current progress to the new progress using easing function.
+ progress = easings.sqrt((now - _smoothScrolling.startTime) / _smoothScrollingDuration);
+
+ renderTop = (_smoothScrolling.startTop + progress * _smoothScrolling.topDiff) | 0;
+ }
+ }
+
+ //Did the scroll position even change?
+ if(_forceRender || _lastTop !== renderTop) {
+ //Remember in which direction are we scrolling?
+ _direction = (renderTop > _lastTop) ? 'down' : (renderTop < _lastTop ? 'up' : _direction);
+
+ _forceRender = false;
+
+ var listenerParams = {
+ curTop: renderTop,
+ lastTop: _lastTop,
+ maxTop: _maxKeyFrame,
+ direction: _direction
+ };
+
+ //Tell the listener we are about to render.
+ var continueRendering = _listeners.beforerender && _listeners.beforerender.call(_instance, listenerParams);
+
+ //The beforerender listener function is able the cancel rendering.
+ if(continueRendering !== false) {
+ //Now actually interpolate all the styles.
+ _calcSteps(renderTop, _instance.getScrollTop());
+
+ //That's were we actually "scroll" on mobile.
+ if(_isMobile && _skrollrBody) {
+ //Set the transform ("scroll it").
+ skrollr.setStyle(_skrollrBody, 'transform', 'translate(0, ' + -(_mobileOffset) + 'px) ' + _translateZ);
+ }
+
+ //Remember when we last rendered.
+ _lastTop = renderTop;
+
+ if(_listeners.render) {
+ _listeners.render.call(_instance, listenerParams);
+ }
+ }
+
+ if(afterAnimationCallback) {
+ afterAnimationCallback.call(_instance, false);
+ }
+ }
+
+ _lastRenderCall = now;
+ };
+
+ /**
+ * Parses the properties for each key frame of the given skrollable.
+ */
+ var _parseProps = function(skrollable) {
+ //Iterate over all key frames
+ var keyFrameIndex = 0;
+ var keyFramesLength = skrollable.keyFrames.length;
+
+ for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
+ var frame = skrollable.keyFrames[keyFrameIndex];
+ var easing;
+ var value;
+ var prop;
+ var props = {};
+
+ var match;
+
+ while((match = rxPropValue.exec(frame.props)) !== null) {
+ prop = match[1];
+ value = match[2];
+
+ easing = prop.match(rxPropEasing);
+
+ //Is there an easing specified for this prop?
+ if(easing !== null) {
+ prop = easing[1];
+ easing = easing[2];
+ } else {
+ easing = DEFAULT_EASING;
+ }
+
+ //Exclamation point at first position forces the value to be taken literal.
+ value = value.indexOf('!') ? _parseProp(value) : [value.slice(1)];
+
+ //Save the prop for this key frame with his value and easing function
+ props[prop] = {
+ value: value,
+ easing: easings[easing]
+ };
+ }
+
+ frame.props = props;
+ }
+ };
+
+ /**
+ * Parses a value extracting numeric values and generating a format string
+ * for later interpolation of the new values in old string.
+ *
+ * @param val The CSS value to be parsed.
+ * @return Something like ["rgba(?%,?%, ?%,?)", 100, 50, 0, .7]
+ * where the first element is the format string later used
+ * and all following elements are the numeric value.
+ */
+ var _parseProp = function(val) {
+ var numbers = [];
+
+ //One special case, where floats don't work.
+ //We replace all occurences of rgba colors
+ //which don't use percentage notation with the percentage notation.
+ rxRGBAIntegerColor.lastIndex = 0;
+ val = val.replace(rxRGBAIntegerColor, function(rgba) {
+ return rgba.replace(rxNumericValue, function(n) {
+ return n / 255 * 100 + '%';
+ });
+ });
+
+ //Handle prefixing of "gradient" values.
+ //For now only the prefixed value will be set. Unprefixed isn't supported anyway.
+ if(theDashedCSSPrefix) {
+ rxGradient.lastIndex = 0;
+ val = val.replace(rxGradient, function(s) {
+ return theDashedCSSPrefix + s;
+ });
+ }
+
+ //Now parse ANY number inside this string and create a format string.
+ val = val.replace(rxNumericValue, function(n) {
+ numbers.push(+n);
+ return '{?}';
+ });
+
+ //Add the formatstring as first value.
+ numbers.unshift(val);
+
+ return numbers;
+ };
+
+ /**
+ * Fills the key frames with missing left and right hand properties.
+ * If key frame 1 has property X and key frame 2 is missing X,
+ * but key frame 3 has X again, then we need to assign X to key frame 2 too.
+ *
+ * @param sk A skrollable.
+ */
+ var _fillProps = function(sk) {
+ //Will collect the properties key frame by key frame
+ var propList = {};
+ var keyFrameIndex;
+ var keyFramesLength;
+
+ //Iterate over all key frames from left to right
+ keyFrameIndex = 0;
+ keyFramesLength = sk.keyFrames.length;
+
+ for(; keyFrameIndex < keyFramesLength; keyFrameIndex++) {
+ _fillPropForFrame(sk.keyFrames[keyFrameIndex], propList);
+ }
+
+ //Now do the same from right to fill the last gaps
+
+ propList = {};
+
+ //Iterate over all key frames from right to left
+ keyFrameIndex = sk.keyFrames.length - 1;
+
+ for(; keyFrameIndex >= 0; keyFrameIndex--) {
+ _fillPropForFrame(sk.keyFrames[keyFrameIndex], propList);
+ }
+ };
+
+ var _fillPropForFrame = function(frame, propList) {
+ var key;
+
+ //For each key frame iterate over all right hand properties and assign them,
+ //but only if the current key frame doesn't have the property by itself
+ for(key in propList) {
+ //The current frame misses this property, so assign it.
+ if(!hasProp.call(frame.props, key)) {
+ frame.props[key] = propList[key];
+ }
+ }
+
+ //Iterate over all props of the current frame and collect them
+ for(key in frame.props) {
+ propList[key] = frame.props[key];
+ }
+ };
+
+ /**
+ * Calculates the new values for two given values array.
+ */
+ var _calcInterpolation = function(val1, val2, progress) {
+ var valueIndex;
+ var val1Length = val1.length;
+
+ //They both need to have the same length
+ if(val1Length !== val2.length) {
+ throw 'Can\'t interpolate between "' + val1[0] + '" and "' + val2[0] + '"';
+ }
+
+ //Add the format string as first element.
+ var interpolated = [val1[0]];
+
+ valueIndex = 1;
+
+ for(; valueIndex < val1Length; valueIndex++) {
+ //That's the line where the two numbers are actually interpolated.
+ interpolated[valueIndex] = val1[valueIndex] + ((val2[valueIndex] - val1[valueIndex]) * progress);
+ }
+
+ return interpolated;
+ };
+
+ /**
+ * Interpolates the numeric values into the format string.
+ */
+ var _interpolateString = function(val) {
+ var valueIndex = 1;
+
+ rxInterpolateString.lastIndex = 0;
+
+ return val[0].replace(rxInterpolateString, function() {
+ return val[valueIndex++];
+ });
+ };
+
+ /**
+ * Resets the class and style attribute to what it was before skrollr manipulated the element.
+ * Also remembers the values it had before reseting, in order to undo the reset.
+ */
+ var _reset = function(elements, undo) {
+ //We accept a single element or an array of elements.
+ elements = [].concat(elements);
+
+ var skrollable;
+ var element;
+ var elementsIndex = 0;
+ var elementsLength = elements.length;
+
+ for(; elementsIndex < elementsLength; elementsIndex++) {
+ element = elements[elementsIndex];
+ skrollable = _skrollables[element[SKROLLABLE_ID_DOM_PROPERTY]];
+
+ //Couldn't find the skrollable for this DOM element.
+ if(!skrollable) {
+ continue;
+ }
+
+ if(undo) {
+ //Reset class and style to the "dirty" (set by skrollr) values.
+ element.style.cssText = skrollable.dirtyStyleAttr;
+ _updateClass(element, skrollable.dirtyClassAttr);
+ } else {
+ //Remember the "dirty" (set by skrollr) class and style.
+ skrollable.dirtyStyleAttr = element.style.cssText;
+ skrollable.dirtyClassAttr = _getClass(element);
+
+ //Reset class and style to what it originally was.
+ element.style.cssText = skrollable.styleAttr;
+ _updateClass(element, skrollable.classAttr);
+ }
+ }
+ };
+
+ /**
+ * Detects support for 3d transforms by applying it to the skrollr-body.
+ */
+ var _detect3DTransforms = function() {
+ _translateZ = 'translateZ(0)';
+ skrollr.setStyle(_skrollrBody, 'transform', _translateZ);
+
+ var computedStyle = getStyle(_skrollrBody);
+ var computedTransform = computedStyle.getPropertyValue('transform');
+ var computedTransformWithPrefix = computedStyle.getPropertyValue(theDashedCSSPrefix + 'transform');
+ var has3D = (computedTransform && computedTransform !== 'none') || (computedTransformWithPrefix && computedTransformWithPrefix !== 'none');
+
+ if(!has3D) {
+ _translateZ = '';
+ }
+ };
+
+ /**
+ * Set the CSS property on the given element. Sets prefixed properties as well.
+ */
+ skrollr.setStyle = function(el, prop, val) {
+ var style = el.style;
+
+ //Camel case.
+ prop = prop.replace(rxCamelCase, rxCamelCaseFn).replace('-', '');
+
+ //Make sure z-index gets a .
+ //This is the only case we need to handle.
+ if(prop === 'zIndex') {
+ if(isNaN(val)) {
+ //If it's not a number, don't touch it.
+ //It could for example be "auto" (#351).
+ style[prop] = val;
+ } else {
+ //Floor the number.
+ style[prop] = '' + (val | 0);
+ }
+ }
+ //#64: "float" can't be set across browsers. Needs to use "cssFloat" for all except IE.
+ else if(prop === 'float') {
+ style.styleFloat = style.cssFloat = val;
+ }
+ else {
+ //Need try-catch for old IE.
+ try {
+ //Set prefixed property if there's a prefix.
+ if(theCSSPrefix) {
+ style[theCSSPrefix + prop.slice(0,1).toUpperCase() + prop.slice(1)] = val;
+ }
+
+ //Set unprefixed.
+ style[prop] = val;
+ } catch(ignore) {}
+ }
+ };
+
+ /**
+ * Cross browser event handling.
+ */
+ var _addEvent = skrollr.addEvent = function(element, names, callback) {
+ var intermediate = function(e) {
+ //Normalize IE event stuff.
+ e = e || window.event;
+
+ if(!e.target) {
+ e.target = e.srcElement;
+ }
+
+ if(!e.preventDefault) {
+ e.preventDefault = function() {
+ e.returnValue = false;
+ e.defaultPrevented = true;
+ };
+ }
+
+ return callback.call(this, e);
+ };
+
+ names = names.split(' ');
+
+ var name;
+ var nameCounter = 0;
+ var namesLength = names.length;
+
+ for(; nameCounter < namesLength; nameCounter++) {
+ name = names[nameCounter];
+
+ if(element.addEventListener) {
+ element.addEventListener(name, callback, false);
+ } else {
+ element.attachEvent('on' + name, intermediate);
+ }
+
+ //Remember the events to be able to flush them later.
+ _registeredEvents.push({
+ element: element,
+ name: name,
+ listener: callback
+ });
+ }
+ };
+
+ var _removeEvent = skrollr.removeEvent = function(element, names, callback) {
+ names = names.split(' ');
+
+ var nameCounter = 0;
+ var namesLength = names.length;
+
+ for(; nameCounter < namesLength; nameCounter++) {
+ if(element.removeEventListener) {
+ element.removeEventListener(names[nameCounter], callback, false);
+ } else {
+ element.detachEvent('on' + names[nameCounter], callback);
+ }
+ }
+ };
+
+ var _removeAllEvents = function() {
+ var eventData;
+ var eventCounter = 0;
+ var eventsLength = _registeredEvents.length;
+
+ for(; eventCounter < eventsLength; eventCounter++) {
+ eventData = _registeredEvents[eventCounter];
+
+ _removeEvent(eventData.element, eventData.name, eventData.listener);
+ }
+
+ _registeredEvents = [];
+ };
+
+ var _emitEvent = function(element, name, direction) {
+ if(_listeners.keyframe) {
+ _listeners.keyframe.call(_instance, element, name, direction);
+ }
+ };
+
+ var _reflow = function() {
+ var pos = _instance.getScrollTop();
+
+ //Will be recalculated by _updateDependentKeyFrames.
+ _maxKeyFrame = 0;
+
+ if(_forceHeight && !_isMobile) {
+ //un-"force" the height to not mess with the calculations in _updateDependentKeyFrames (#216).
+ body.style.height = '';
+ }
+
+ _updateDependentKeyFrames();
+
+ if(_forceHeight && !_isMobile) {
+ //"force" the height.
+ body.style.height = (_maxKeyFrame + documentElement.clientHeight) + 'px';
+ }
+
+ //The scroll offset may now be larger than needed (on desktop the browser/os prevents scrolling farther than the bottom).
+ if(_isMobile) {
+ _instance.setScrollTop(Math.min(_instance.getScrollTop(), _maxKeyFrame));
+ } else {
+ //Remember and reset the scroll pos (#217).
+ _instance.setScrollTop(pos, true);
+ }
+
+ _forceRender = true;
+ };
+
+ /*
+ * Returns a copy of the constants object where all functions and strings have been evaluated.
+ */
+ var _processConstants = function() {
+ var viewportHeight = documentElement.clientHeight;
+ var copy = {};
+ var prop;
+ var value;
+
+ for(prop in _constants) {
+ value = _constants[prop];
+
+ if(typeof value === 'function') {
+ value = value.call(_instance);
+ }
+ //Percentage offset.
+ else if((/p$/).test(value)) {
+ value = (value.slice(0, -1) / 100) * viewportHeight;
+ }
+
+ copy[prop] = value;
+ }
+
+ return copy;
+ };
+
+ /*
+ * Returns the height of the document.
+ */
+ var _getDocumentHeight = function() {
+ var skrollrBodyHeight = 0;
+ var bodyHeight;
+
+ if(_skrollrBody) {
+ skrollrBodyHeight = Math.max(_skrollrBody.offsetHeight, _skrollrBody.scrollHeight);
+ }
+
+ bodyHeight = Math.max(skrollrBodyHeight, body.scrollHeight, body.offsetHeight, documentElement.scrollHeight, documentElement.offsetHeight, documentElement.clientHeight);
+
+ return bodyHeight - documentElement.clientHeight;
+ };
+
+ /**
+ * Returns a string of space separated classnames for the current element.
+ * Works with SVG as well.
+ */
+ var _getClass = function(element) {
+ var prop = 'className';
+
+ //SVG support by using className.baseVal instead of just className.
+ if(window.SVGElement && element instanceof window.SVGElement) {
+ element = element[prop];
+ prop = 'baseVal';
+ }
+
+ return element[prop];
+ };
+
+ /**
+ * Adds and removes a CSS classes.
+ * Works with SVG as well.
+ * add and remove are arrays of strings,
+ * or if remove is ommited add is a string and overwrites all classes.
+ */
+ var _updateClass = function(element, add, remove) {
+ var prop = 'className';
+
+ //SVG support by using className.baseVal instead of just className.
+ if(window.SVGElement && element instanceof window.SVGElement) {
+ element = element[prop];
+ prop = 'baseVal';
+ }
+
+ //When remove is ommited, we want to overwrite/set the classes.
+ if(remove === undefined) {
+ element[prop] = add;
+ return;
+ }
+
+ //Cache current classes. We will work on a string before passing back to DOM.
+ var val = element[prop];
+
+ //All classes to be removed.
+ var classRemoveIndex = 0;
+ var removeLength = remove.length;
+
+ for(; classRemoveIndex < removeLength; classRemoveIndex++) {
+ val = _untrim(val).replace(_untrim(remove[classRemoveIndex]), ' ');
+ }
+
+ val = _trim(val);
+
+ //All classes to be added.
+ var classAddIndex = 0;
+ var addLength = add.length;
+
+ for(; classAddIndex < addLength; classAddIndex++) {
+ //Only add if el not already has class.
+ if(_untrim(val).indexOf(_untrim(add[classAddIndex])) === -1) {
+ val += ' ' + add[classAddIndex];
+ }
+ }
+
+ element[prop] = _trim(val);
+ };
+
+ var _trim = function(a) {
+ return a.replace(rxTrim, '');
+ };
+
+ /**
+ * Adds a space before and after the string.
+ */
+ var _untrim = function(a) {
+ return ' ' + a + ' ';
+ };
+
+ var _now = Date.now || function() {
+ return +new Date();
+ };
+
+ var _keyFrameComparator = function(a, b) {
+ return a.frame - b.frame;
+ };
+
+ /*
+ * Private variables.
+ */
+
+ //Singleton
+ var _instance;
+
+ /*
+ A list of all elements which should be animated associated with their the metadata.
+ Exmaple skrollable with two key frames animating from 100px width to 20px:
+
+ skrollable = {
+ element: ,
+ styleAttr: