wpj.domUtils = { crossFade: function ($old, $new, complete) { var width, height = $old.outerHeight(true), speed = 300; if ($old[0].getBoundingClientRect().width) width = $old[0].getBoundingClientRect().width; else width = $old.outerWidth(true); if (width <= 0) { $old.before($new).hide(); if (complete) complete($old, $new); else $old.remove(); return; } var $positionWrap = $old.wrap($('
').width(width).height(height)).parent(), $oldWrap = $old.wrap('
').parent(), $newWrap = $new.wrap('
').parent(); $newWrap.css({opacity: 0}); $positionWrap.append($newWrap); $new.trigger('crossFaded'); $oldWrap.animate({opacity: 0}, speed); $newWrap.animate({opacity: 1}, speed, undefined, function() { $oldWrap.unwrap(); $old.unwrap(); $new.unwrap(); if (complete) complete($old, $new); else $old.remove(); }); var new_height = $newWrap.height(), old_height = $positionWrap.height(); if (old_height != new_height) $positionWrap.animate({height: new_height}, speed); }, reloadParts: function($selector, dataPromise, finishedCallback) { // Set all parts to loading state $selector.addClass('reload-loading').animate({opacity: 0.66}, 300); dataPromise.done(function($html){ var newParts = wpj.domUtils.crossFadeParts($selector, $html); $selector.removeClass('reload-loading'); if (finishedCallback) finishedCallback(newParts); }); }, crossFadeParts: function($oldParts, $newHtml) { var $oldPart, $newPart, newParts = [], selector; $oldParts.each(function(){ $oldPart = $(this); selector = '[data-reload="'+$oldPart.data('reload')+'"]'; $newPart = $newHtml.find(selector).addBack(selector); $.merge(newParts, $newPart); if ($oldPart.closest('.crossfade-wrapper').length || !document.documentElement.contains(this)) { // console.log('$old', 'in crossfade', $oldPart.closest('.crossfade-wrapper').length, 'removed', !document.documentElement.contains(this)); $oldPart = $('[data-reload="'+$oldPart.data('reload')+'"]'); if ($oldPart.length > 1) $oldPart = $oldPart.filter('.crossfade-position.new > [data-reload]'); $oldPart.html($newPart.html()); return; } if (!$newPart.length) { // Create dummy empty element if element not in result $newPart = $('
').attr('data-reload', $oldPart.data('reload')); } wpj.domUtils.crossFade($oldPart, $newPart); }); return newParts; }, reloadPartsFromUrl: function(url, $oldParts, data) { // Load new category products var dataLoaded = $.Deferred(), method = data ? 'post' : 'get'; wpj.domUtils.reloadParts($oldParts, dataLoaded); $[method](url, data, function (data) { dataLoaded.resolve(wpj.domUtils.parseHtml(data)); }); }, getHash: function() { return location.href.split("#")[1] || ""; }, parseHtml: function (html, selector) { var $content = $("
").append($.parseHTML(html, true)); if (selector) return $content.find(selector); else return $content.children(); }, scrollTo: function ($anchor, speed) { var offset = $anchor.offset(); if (speed == undefined) speed = 1000; if (offset) { $('html, body').stop().animate({ scrollTop: offset.top - 100 }, speed); } }, activeTimers: {}, resetTimer: function (id, timeout, callback) { var timers = wpj.domUtils.activeTimers, timer = timers[id]; if (timer) clearTimeout(timer); timers[id] = setTimeout(function () { delete timers[id]; callback(); }, timeout); }, initOpeners: function($selector) { if (!$selector) $selector = $('body'); // Disable animation during init to avoid reflows $.fx.off = true; var event = 'change'; if (!$selector.is('input')) event = 'click'; $selector.on(event + ' update', '[data-opener]', function(e){ var $this = $(e.currentTarget), $target = $($this.data('opener')), checked; if ($this.is('input')) checked = $this.is(':checked'); else { checked = $this.is('.active'); if (e.type != 'update') checked = !checked; } $target[checked ? 'slideDown' : 'slideUp']()[checked ? 'addClass' : 'removeClass']('active').trigger('opened'); $this[checked ? 'addClass' : 'removeClass']('active'); return !$this.is('a'); }) // Trigger change event on init to update target visibility .find('[data-opener]').trigger('update'); $.fx.off = false; }, isInView: function ($elem) { var $window = $(window), docViewTop = $window.scrollTop(), docViewBottom = docViewTop + $window.height(), elemTop = $elem.offset().top, elemBottom = elemTop + $elem.height(); return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); }, /** * @param {HTMLElement} openerHtmlElement */ expandOpener: function (openerHtmlElement) { var $opener = $(openerHtmlElement); $opener.addClass('active'); $opener.trigger('update'); } };