From 72d327e1fbba536fc32e478a12b4fb5c0bb6ea75 Mon Sep 17 00:00:00 2001 From: mAAdhaTTah Date: Fri, 7 Apr 2017 22:04:49 -0400 Subject: [PATCH 1/6] Remove jQuery dependency from `attr-persistence` Add `camelCase` dependency to handle one of jQuery's features that we depend upon. --- lib/attr-persistence.js | 17 ++++++++++------- package.json | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/attr-persistence.js b/lib/attr-persistence.js index 83397f9..57c9604 100644 --- a/lib/attr-persistence.js +++ b/lib/attr-persistence.js @@ -1,6 +1,6 @@ 'use strict'; -var $ = require('jquery'); +var camelCase = require('camelcase'); /** * Helps persist class names or css rules across calls to morphdom. @@ -24,25 +24,28 @@ function persistAttr(fromEl, toEl, type) { if (type !== 'class' && type !== 'css') { throw new Error('unsupported type ' + type); } - var $from = $(fromEl); var attr = 'data-persist-' + type; - var toPersist = $from.attr(attr); + var toPersist = fromEl.getAttribute(attr); if (!toPersist) { return toEl; } toPersist = toPersist.split(','); - var $to = $(toEl); for (var i = 0; i < toPersist.length; i++) { var curClass = toPersist[i]; switch (type) { case 'class': - $to.toggleClass(toPersist[i], $from.hasClass(curClass)); + if (fromEl.classList.contains(curClass)) { + toEl.classList.add(toPersist[i]); + } else { + toEl.classList.remove(toPersist[i]); + } break; case 'css': // Avoid persisting styles that are computed and not strictly // defined on the style attribute - if ($from.get(0).style[$.camelCase(curClass)]) { - $to.css(curClass, $from.css(curClass)); + var style = camelCase(curClass); + if (fromEl.style[style]) { + toEl.style[style] = fromEl.style[style]; } break; default: diff --git a/package.json b/package.json index 6bdf870..59189b5 100644 --- a/package.json +++ b/package.json @@ -64,5 +64,8 @@ }, "roux": { "pantryRoot": "sass-mixins" + }, + "dependencies": { + "camelcase": "^3.0.0" } } From af16f98077fa2e8f3ed1614ca241de4de4798dd3 Mon Sep 17 00:00:00 2001 From: mAAdhaTTah Date: Fri, 7 Apr 2017 22:10:37 -0400 Subject: [PATCH 2/6] Remove jQuery from css-transition-group --- lib/css-transition-group.js | 73 +++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/lib/css-transition-group.js b/lib/css-transition-group.js index 9f7a8e7..149396a 100644 --- a/lib/css-transition-group.js +++ b/lib/css-transition-group.js @@ -1,7 +1,5 @@ 'use strict'; -var $ = require('jquery'); - var TRANSITION_ATTR = 'data-transition-name'; var TRANSITION_ENTER_ATTR = 'data-transition-enter'; var TRANSITION_LEAVE_ATTR = 'data-transition-leave'; @@ -38,48 +36,47 @@ module.exports.plugin = function () { * value of the specified attribute does not parse as an integer. * @memberOf cssTransitionGroup * @param {String} attr name of attribute from which to fetch an integer. - * @param {jQuery} $node jQuery collection containing the node in question. + * @param {Element} node jQuery collection containing the node in question. * @return {Number} number representing the value of the attr for the * $node */ -function getTransitionTimeout(attr, $node, defaultDuration) { +function getTransitionTimeout(attr, node, defaultDuration) { if (typeof defaultDuration === 'undefined') { defaultDuration = NaN; } - var transitionTimeout = $node.attr(attr); + var transitionTimeout = node.getAttribute(attr); transitionTimeout = transitionTimeout ? parseInt(transitionTimeout, 10) : defaultDuration; if (isNaN(transitionTimeout)) { var e = Error(attr + ' must be an integer'); - e.forNode = $node.get(0); + e.forNode = node; throw e; } return transitionTimeout; } function onBeforeNodeAdded(node) { - var $node = $(node); - var transitionName = $node.attr(TRANSITION_ATTR); + var transitionName = node.getAttribute && node.getAttribute(TRANSITION_ATTR); if (!transitionName) { return node; } - var transitionIsEnabled = $node.attr(TRANSITION_ENTER_ATTR); + var transitionIsEnabled = node.getAttribute(TRANSITION_ENTER_ATTR); if (transitionIsEnabled === 'false') { return; } var transitionEnterTimeout = getTransitionTimeout( - TRANSITION_ENTER_DELAY_ATTR, $node, 65 + TRANSITION_ENTER_DELAY_ATTR, node, 65 ); var transitionDuration = getTransitionTimeout( - TRANSITION_ENTER_DURATION_ATTR, $node + TRANSITION_ENTER_DURATION_ATTR, node ); - $node.addClass(transitionName + ENTER_SUFFIX); + node.classList.add(transitionName + ENTER_SUFFIX); function applyEnterTransition() { - $node.addClass(transitionName + ENTER_SUFFIX + ACTIVE_SUFFIX); + node.classList.add(transitionName + ENTER_SUFFIX + ACTIVE_SUFFIX); setTimeout(function () { - $node.removeClass(transitionName + ENTER_SUFFIX); - $node.removeClass(transitionName + ENTER_SUFFIX + ACTIVE_SUFFIX); - $node.trigger(transitionName + ENTER_SUFFIX + COMPLETE_SUFFIX); + node.classList.remove(transitionName + ENTER_SUFFIX); + node.classList.remove(transitionName + ENTER_SUFFIX + ACTIVE_SUFFIX); + dispatchEvent(node, transitionName + ENTER_SUFFIX + COMPLETE_SUFFIX); }, transitionDuration); } setTimeout(applyEnterTransition, transitionEnterTimeout); @@ -87,43 +84,40 @@ function onBeforeNodeAdded(node) { } function onBeforeNodeDiscarded(node) { - var $node = $(node); - var transitionName = $node.attr(TRANSITION_ATTR); + var transitionName = node.getAttribute && node.getAttribute(TRANSITION_ATTR); if (!transitionName) { return true; } - var transitionIsEnabled = $node.attr(TRANSITION_LEAVE_ATTR); + var transitionIsEnabled = node.getAttribute(TRANSITION_LEAVE_ATTR); if (transitionIsEnabled === 'false') { return true; } var transitionLeaveTimeout = getTransitionTimeout( - TRANSITION_LEAVE_DELAY_ATTR, $node, 65 + TRANSITION_LEAVE_DELAY_ATTR, node, 65 ); var transitionDuration = getTransitionTimeout( - TRANSITION_LEAVE_DURATION_ATTR, $node + TRANSITION_LEAVE_DURATION_ATTR, node ); node._totalDuration = transitionLeaveTimeout + transitionDuration; node._leaveStart = new Date().getTime(); - $node.addClass(transitionName + LEAVE_SUFFIX); + node.classList.add(transitionName + LEAVE_SUFFIX); clearTimeout(node._leaveTimeout); node._leaveTimeout = setTimeout(applyLeaveTransition, transitionLeaveTimeout); function applyLeaveTransition() { - $node.addClass(transitionName + LEAVE_SUFFIX + ACTIVE_SUFFIX); + node.classList.add(transitionName + LEAVE_SUFFIX + ACTIVE_SUFFIX); node._leaveTimeout = setTimeout(handleLeaveTransitionComplete, transitionDuration); } function handleLeaveTransitionComplete() { node._leaveTimeout = null; - $node.trigger(transitionName + LEAVE_SUFFIX + COMPLETE_SUFFIX); - $node.remove(); + dispatchEvent(node, transitionName + LEAVE_SUFFIX + COMPLETE_SUFFIX); + node.parentNode.removeChild(node); } return false; } function onBeforeElUpdated(fromEl, toEl) { - var $from = $(fromEl); - var $to = $(toEl); - var transitionName = $from.attr(TRANSITION_ATTR); + var transitionName = fromEl.getAttribute && fromEl.getAttribute(TRANSITION_ATTR); if (!transitionName) { return toEl; } @@ -133,11 +127,11 @@ function onBeforeElUpdated(fromEl, toEl) { // is now intended to be in the dom. Cancel and reverse the exit transition. if (fromEl._leaveTimeout) { fromEl._leaveTimeout = clearTimeout(fromEl._leaveTimeout); - $from.addClass(transitionName + LEAVE_SUFFIX); - $from.removeClass(transitionName + LEAVE_SUFFIX + ACTIVE_SUFFIX); + fromEl.classList.add(transitionName + LEAVE_SUFFIX); + fromEl.classList.remove(transitionName + LEAVE_SUFFIX + ACTIVE_SUFFIX); var remaining = fromEl._totalDuration - (new Date().getTime() - fromEl._leaveStart); fromEl._leaveTimeout = setTimeout(function () { - $from.removeClass(transitionName + LEAVE_SUFFIX); + fromEl.classList.remove(transitionName + LEAVE_SUFFIX); }, remaining); } var transitionClassesToPersist = [ @@ -148,7 +142,22 @@ function onBeforeElUpdated(fromEl, toEl) { ]; for (var i = 0; i < transitionClassesToPersist.length; i++) { var name = transitionClassesToPersist[i]; - $to.toggleClass(name, $from.hasClass(name)); + if (fromEl.classList.contains(name)) { + toEl.classList.add(name); + } else { + toEl.classList.remove(name); + } } return toEl; } + +function dispatchEvent(node, event) { + var evt; + try { + evt = new Event(event, {bubbles: true}); + } catch (e) { + evt = document.createEvent('Event'); + evt.initEvent(event, true, true); + } + node.dispatchEvent(evt); +} From 98ffdf3084675594440dfa33e4a09470e9a4af97 Mon Sep 17 00:00:00 2001 From: mAAdhaTTah Date: Mon, 10 Apr 2017 22:48:57 -0400 Subject: [PATCH 3/6] Reove jQuery from input-persistence Add `matches` polyfill for cross-browser usage. --- lib/input-persistence.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/input-persistence.js b/lib/input-persistence.js index fcf0ac9..4adad81 100644 --- a/lib/input-persistence.js +++ b/lib/input-persistence.js @@ -1,6 +1,22 @@ 'use strict'; -var $ = require('jquery'); +var Element = window.Element; + +// @source: MDN +if (!Element.prototype.matches) { + Element.prototype.matches = + Element.prototype.matchesSelector || + Element.prototype.mozMatchesSelector || + Element.prototype.msMatchesSelector || + Element.prototype.oMatchesSelector || + Element.prototype.webkitMatchesSelector || + function (s) { + var matches = (this.document || this.ownerDocument).querySelectorAll(s), + i = matches.length; + while (--i >= 0 && matches.item(i) !== this) {} + return i > -1; + }; +} /** * There exists a possible race condition where the following conditions are @@ -35,7 +51,7 @@ var $ = require('jquery'); module.exports.plugin = function () { return { onBeforeElUpdated: function (el) { - return !$(el).is('input[type=text]:focus,input[type=number]:focus'); + return !el.matches('input[type=text]:focus,input[type=number]:focus'); } }; }; From 9263cc82c1180f0b684396a2be310014ef6f2c0e Mon Sep 17 00:00:00 2001 From: mAAdhaTTah Date: Tue, 11 Apr 2017 10:33:43 -0400 Subject: [PATCH 4/6] Remove jQuery from transition-element-movement --- lib/transition-element-movement.js | 59 ++++++++++++++++-------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/lib/transition-element-movement.js b/lib/transition-element-movement.js index f56a7b4..3addff6 100644 --- a/lib/transition-element-movement.js +++ b/lib/transition-element-movement.js @@ -3,8 +3,6 @@ // Motivation for transitioning positional changes inspired by // https://medium.com/developers-writing/animating-the-unanimatable-1346a5aab3cd -var $ = require('jquery'); - var TRANSITION_ATTR = 'data-transition-motion'; var TRANSITION_MOTION_DURATION_ATTR = 'data-transition-motion-duration'; var TRANSITION_MOTION_CLASS_ATTR = 'data-transition-motion-class'; @@ -19,9 +17,7 @@ var DEFAULT_TRANSITION_MOTION_CLASS = 'transition-motion'; module.exports.plugin = function () { return { onBeforeElUpdated: function onBeforeElUpdated(fromEl, toEl) { - var $from = $(fromEl); - var $to = $(toEl); - var transitionName = $from.attr(TRANSITION_ATTR); + var transitionName = fromEl.getAttribute(TRANSITION_ATTR); if (!transitionName) { return toEl; } @@ -36,16 +32,14 @@ module.exports.plugin = function () { // If we've already done this once, $from.css('transform') will have // a value. If that is the case, we copy it from $from to $to and // return - if ($from.css('transform') !== 'none') { - $to.css({ - transform: $from.css('transform') - }); + if (getTransform(fromEl)) { + setTransform(toEl, getTransform(fromEl)); return toEl; } - var activateMotionTransitionClass = $from.attr(TRANSITION_MOTION_CLASS_ATTR) || + var activateMotionTransitionClass = fromEl.getAttribute(TRANSITION_MOTION_CLASS_ATTR) || DEFAULT_TRANSITION_MOTION_CLASS; - var motionDuration = $from.attr(TRANSITION_MOTION_DURATION_ATTR); + var motionDuration = fromEl.getAttribute(TRANSITION_MOTION_DURATION_ATTR); motionDuration = parseInt(motionDuration, 10); if (isNaN(motionDuration)) { throw new Error( @@ -74,25 +68,18 @@ module.exports.plugin = function () { // the dom. Thus, at this point of the code execution, the state // of `fromEl === (the state of toEl)` when the // `onBeforeElUpdated` method returned. - $from.css({ - height: previousPosition.height, - width: previousPosition.width, - transform: 'translate(' + deltaX + 'px ,' + - deltaY + 'px)' - }); + fromEl.style.height = previousPosition.height + 'px'; + fromEl.style.width = previousPosition.width + 'px'; + setTransform(fromEl, 'translate(' + deltaX + 'px ,' + deltaY + 'px)'); window.requestAnimationFrame(function () { - $from.addClass(activateMotionTransitionClass); - $from.css({ - transform: '', - height: newPosition.height, - width: newPosition.width - }); + fromEl.classList.add(activateMotionTransitionClass); + setTransform(fromEl, ''); + fromEl.style.height = newPosition.height + 'px'; + fromEl.style.width = newPosition.width + 'px'; setTimeout(function () { - $from.removeClass(activateMotionTransitionClass); - $from.css({ - height: '', - width: '' - }); + fromEl.classList.remove(activateMotionTransitionClass); + fromEl.style.height = ''; + fromEl.style.width = ''; }, motionDuration); }); }); @@ -100,3 +87,19 @@ module.exports.plugin = function () { } }; }; + +function setTransform(element, transform) { + element.style.webkitTransform = transform; + element.style.MozTransform = transform; + element.style.msTransform = transform; + element.style.OTransform = transform; + element.style.transform = transform; +} + +function getTransform(element) { + return element.style.webkitTransform || + element.style.MozTransform || + element.style.msTransform || + element.style.OTransform || + element.style.transform || ''; +} From d142afc6fb81c33fbf693cc9f07d151039a35a7e Mon Sep 17 00:00:00 2001 From: mAAdhaTTah Date: Tue, 11 Apr 2017 10:52:49 -0400 Subject: [PATCH 5/6] Remove jQuery from transition-height --- lib/transition-height.js | 74 +++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 42 deletions(-) diff --git a/lib/transition-height.js b/lib/transition-height.js index 8fb2ea7..d57dc09 100644 --- a/lib/transition-height.js +++ b/lib/transition-height.js @@ -1,7 +1,5 @@ 'use strict'; -var $ = require('jquery'); - var TRANSITION_ATTR = 'data-transition-height'; var TRANSITION_TARGET_ATTR = 'data-transition-height-target'; var ELEMENT_IS_COLLAPSED_CLASS_ATTR = 'data-transition-height-collapsed-class'; @@ -20,25 +18,26 @@ var TRANSITION_ON_ADDED_DELAY = 'data-transition-height-on-added-delay'; module.exports.plugin = function () { return { onNodeAdded: function onNodeAdded(el) { - var $el = $(el); - var transitionOnAdded = $el.attr(TRANSITION_ON_ADDED_ATTR); + // Skip text nodes. + if (el.nodeType === 3) { + return; + } + var transitionOnAdded = el.getAttribute(TRANSITION_ON_ADDED_ATTR); if (transitionOnAdded !== 'true') { - var transitionName = $el.attr(TRANSITION_ATTR); + var transitionName = el.getAttribute(TRANSITION_ATTR); if (transitionName !== 'true') { return; } - var collapsedClass = $el.attr(ELEMENT_IS_COLLAPSED_CLASS_ATTR) || + var collapsedClass = el.getAttribute(ELEMENT_IS_COLLAPSED_CLASS_ATTR) || DEFAULT_ELEMENT_IS_COLLAPSED_CLASS; - var isOpen = !$el.hasClass(collapsedClass); + var isOpen = !el.classList.contains(collapsedClass); if (isOpen) { - var newHeight = getProperElementHeight($el); - $el.css({ - 'max-height': newHeight + 'px' - }); + var newHeight = getProperElementHeight(el); + el.style.maxHeight = newHeight + 'px'; } return; } - var transitionTimeout = $el.attr(TRANSITION_ON_ADDED_DELAY); + var transitionTimeout = el.getAttribute(TRANSITION_ON_ADDED_DELAY); transitionTimeout = transitionTimeout ? parseInt(transitionTimeout, 10) : 65; if (isNaN(transitionTimeout)) { @@ -49,21 +48,17 @@ module.exports.plugin = function () { // Call this function now to ensure it will not throw an error // after we set the timeout - getProperElementHeight($el); + getProperElementHeight(el); setTimeout(function () { - var newHeight = getProperElementHeight($el); - $el.css({ - 'max-height': newHeight + 'px' - }); + var newHeight = getProperElementHeight(el); + el.style.maxHeight = newHeight + 'px'; }, transitionTimeout); return el; }, onBeforeElUpdated: function onBeforeElUpdated(fromEl, toEl) { - var $from = $(fromEl); - var $to = $(toEl); - var transitionName = $from.attr(TRANSITION_ATTR); + var transitionName = fromEl.getAttribute(TRANSITION_ATTR); if (transitionName !== 'true') { - var transitionOnAdded = $from.attr(TRANSITION_ON_ADDED_ATTR); + var transitionOnAdded = fromEl.getAttribute(TRANSITION_ON_ADDED_ATTR); if (transitionOnAdded !== 'true') { return; } @@ -78,10 +73,8 @@ module.exports.plugin = function () { // by the time the animation frame has been requested, // morphdom has applied the changes on toEl to fromEl // that is why we update $from here - var newHeight = getProperElementHeight($from); - $from.css({ - 'max-height': newHeight + 'px' - }); + var newHeight = getProperElementHeight(fromEl); + fromEl.style.maxHeight = newHeight + 'px'; }); return toEl; } @@ -93,14 +86,12 @@ module.exports.plugin = function () { // the height of its immediate child to determine the target height // for $to thus, we modify toEl directly before returning it to // morphdom - var collapsedClass = $from.attr(ELEMENT_IS_COLLAPSED_CLASS_ATTR) || + var collapsedClass = fromEl.getAttribute(ELEMENT_IS_COLLAPSED_CLASS_ATTR) || DEFAULT_ELEMENT_IS_COLLAPSED_CLASS; - var isOpen = !$to.hasClass(collapsedClass); + var isOpen = !toEl.classList.contains(collapsedClass); if (isOpen) { - var newHeight = getProperElementHeight($from); - $to.css({ - 'max-height': newHeight + 'px' - }); + var newHeight = getProperElementHeight(fromEl); + toEl.style.maxHeight = newHeight + 'px'; } return toEl; } @@ -108,26 +99,25 @@ module.exports.plugin = function () { }; module.exports.resizeHandler = function () { - $('[' + TRANSITION_ON_ADDED_ATTR + '=true],[' + TRANSITION_ATTR + '=true]') - .each(function (idx, el) { - var $el = $(el); - $el.css( - 'max-height', - getProperElementHeight($el) - ); + var els = document.querytSelectorAll( + '[' + TRANSITION_ON_ADDED_ATTR + '=true],[' + TRANSITION_ATTR + '=true]' + ); + + Array.prototype.forEach.call(els, function (el) { + el.style.maxHeight = getProperElementHeight(el) + 'px'; }); }; -function getProperElementHeight($element) { - var $heightTarget = $element.children( +function getProperElementHeight(element) { + var heightTarget = element.querySelectorAll( '[' + TRANSITION_TARGET_ATTR + '="true"]' ); - if ($heightTarget.length !== 1 || $element.children().length !== 1) { + if (heightTarget.length !== 1 || element.children.length !== 1) { throw new Error( 'Element with ' + TRANSITION_ATTR + ' needs to have precisely one child with [' + TRANSITION_TARGET_ATTR + '="true"]' ); } - return $heightTarget.outerHeight(); + return heightTarget[0].clientHeight; } From 31fb0cce938c3e9e403eaa73397223e91f9b3944 Mon Sep 17 00:00:00 2001 From: mAAdhaTTah Date: Tue, 11 Apr 2017 22:33:07 -0400 Subject: [PATCH 6/6] Set eslint env to mocha ESLint has a setting for mocha, so we don't have to define the globals ourselves. --- tests/.eslintrc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/.eslintrc b/tests/.eslintrc index 4169c8a..0db357c 100644 --- a/tests/.eslintrc +++ b/tests/.eslintrc @@ -1,8 +1,7 @@ # vim: set syntax=yaml: --- extends: "../node_modules/@retailmenot/core-ui-eslintrc/.eslintrc-es6" - globals: - it: true - describe: true + env: + mocha: true rules: max-len: [2, 100]