diff --git a/src/scripts/lib/switches-selectors.js b/src/scripts/lib/switches-selectors.js new file mode 100644 index 0000000..5ae919f --- /dev/null +++ b/src/scripts/lib/switches-selectors.js @@ -0,0 +1,35 @@ +var forEachEls = require("./foreach-els") + +var defaultSwitches = require("./switches") + +module.exports = function(switches, switchesOptions, selectors, fromEl, toEl, options) { + selectors.forEach(function(selector) { + var newEls = fromEl.querySelectorAll(selector) + var oldEls = toEl.querySelectorAll(selector) + if (this.log) { + this.log("Pjax switch", selector, newEls, oldEls) + } + if (newEls.length !== oldEls.length) { + // forEachEls(newEls, function(el) { + // this.log("newEl", el, el.outerHTML) + // }, this) + // forEachEls(oldEls, function(el) { + // this.log("oldEl", el, el.outerHTML) + // }, this) + throw "DOM doesn’t look the same on new loaded page: ’" + selector + "’ - new " + newEls.length + ", old " + oldEls.length + } + + forEachEls(newEls, function(newEl, i) { + var oldEl = oldEls[i] + if (this.log) { + this.log("newEl", newEl, "oldEl", oldEl) + } + if (switches[selector]) { + switches[selector].bind(this)(oldEl, newEl, options, switchesOptions[selector]) + } + else { + defaultSwitches.outerHTML.bind(this)(oldEl, newEl, options) + } + }, this) + }, this) +} diff --git a/src/scripts/lib/switches.js b/src/scripts/lib/switches.js new file mode 100644 index 0000000..af14c43 --- /dev/null +++ b/src/scripts/lib/switches.js @@ -0,0 +1,110 @@ +module.exports = { + outerHTML: function(oldEl, newEl, options) { + oldEl.outerHTML = newEl.outerHTML + this.onSwitch() + }, + + innerHTML: function(oldEl, newEl, options) { + oldEl.innerHTML = newEl.innerHTML + oldEl.className = newEl.className + this.onSwitch() + }, + + sideBySide: function(oldEl, newEl, options, switchOptions) { + var forEach = Array.prototype.forEach + var elsToRemove = [] + var elsToAdd = [] + var fragToAppend = document.createDocumentFragment() + // height transition are shitty on safari + // so commented for now (until I found something ?) + //var relevantHeight = 0 + var animationEventNames = "animationend webkitAnimationEnd MSAnimationEnd oanimationend" + var animatedElsNumber = 0 + var sexyAnimationEnd = function(e) { + if (e.target != e.currentTarget) { + // end triggered by an animation on a child + return + } + + animatedElsNumber-- + if (animatedElsNumber <= 0 && elsToRemove) { + elsToRemove.forEach(function(el) { + // browsing quickly can make the el + // already removed by last page update ? + if (el.parentNode) { + el.parentNode.removeChild(el) + } + }) + + elsToAdd.forEach(function(el) { + el.className = el.className.replace(el.getAttribute("data-pjax-classes"), "") + el.removeAttribute("data-pjax-classes") + // Pjax.off(el, animationEventNames, sexyAnimationEnd, true) + }) + + elsToAdd = null // free memory + elsToRemove = null // free memory + + // assume the height is now useless (avoid bug since there is overflow hidden on the parent) + // oldEl.style.height = "auto" + + // this is to trigger some repaint (example: picturefill) + this.onSwitch() + //Pjax.trigger(window, "scroll") + } + }.bind(this) + + // Force height to be able to trigger css animation + // here we get the relevant height + // oldEl.parentNode.appendChild(newEl) + // relevantHeight = newEl.getBoundingClientRect().height + // oldEl.parentNode.removeChild(newEl) + // oldEl.style.height = oldEl.getBoundingClientRect().height + "px" + + switchOptions = switchOptions || {} + + forEach.call(oldEl.childNodes, function(el) { + elsToRemove.push(el) + if (el.classList && !el.classList.contains("js-Pjax-remove")) { + // for fast switch, clean element that just have been added, & not cleaned yet. + if (el.hasAttribute("data-pjax-classes")) { + el.className = el.className.replace(el.getAttribute("data-pjax-classes"), "") + el.removeAttribute("data-pjax-classes") + } + el.classList.add("js-Pjax-remove") + if (switchOptions.callbacks && switchOptions.callbacks.removeElement) { + switchOptions.callbacks.removeElement(el) + } + if (switchOptions.classNames) { + el.className += " " + switchOptions.classNames.remove + " " + (options.backward ? switchOptions.classNames.backward : switchOptions.classNames.forward) + } + animatedElsNumber++ + Pjax.on(el, animationEventNames, sexyAnimationEnd, true) + } + }) + + forEach.call(newEl.childNodes, function(el) { + if (el.classList) { + var addClasses = "" + if (switchOptions.classNames) { + addClasses = " js-Pjax-add " + switchOptions.classNames.add + " " + (options.backward ? switchOptions.classNames.forward : switchOptions.classNames.backward) + } + if (switchOptions.callbacks && switchOptions.callbacks.addElement) { + switchOptions.callbacks.addElement(el) + } + el.className += addClasses + el.setAttribute("data-pjax-classes", addClasses) + elsToAdd.push(el) + fragToAppend.appendChild(el) + animatedElsNumber++ + Pjax.on(el, animationEventNames, sexyAnimationEnd, true) + } + }) + + // pass all className of the parent + oldEl.className = newEl.className + oldEl.appendChild(fragToAppend) + + // oldEl.style.height = relevantHeight + "px" + } +} diff --git a/tests/scripts/lib/switch-selectors.js b/tests/scripts/lib/switch-selectors.js new file mode 100644 index 0000000..0d5bb80 --- /dev/null +++ b/tests/scripts/lib/switch-selectors.js @@ -0,0 +1,9 @@ +var tape = require("tape") + +var switchesSelectors = require("../../../src/scripts/lib/switches-selectors.js") + +tape("test switchesSelectors", function(t) { + t.fail() + + t.end() +})