Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop jQuery #59

Merged
merged 22 commits into from
Sep 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dd3b823
[Chore] estatico-boilerplate: Optimized global client-side namespace
backflip Sep 15, 2018
3edd916
[Fix] estatico-boilerplate: Fixed slideshow test after namespace abst…
backflip Sep 15, 2018
9dcfdd4
[Chore] estatico-boilerplate: Changed module class name
backflip Sep 16, 2018
ce0630b
[Chore] estatico-boilerplate: Moved dev styles and scripts into /preview
backflip Sep 16, 2018
f56af5b
Merge remote-tracking branch 'origin/develop' into feature/namespace
backflip Sep 16, 2018
7aabe17
Merge remote-tracking branch 'origin/develop' into feature/dev-js
backflip Sep 16, 2018
fea5e97
Merge branch 'feature/namespace' into develop
backflip Sep 16, 2018
90bd71c
Merge branch 'feature/dev-js' into develop
backflip Sep 16, 2018
53a71ae
[Fix] estatico-boilerplate: Fixed path in moved dev.js
backflip Sep 16, 2018
7667566
[Change] estatico-boilerplate: Removed jQuery
backflip Sep 16, 2018
0e6c2b9
[Change] estatico-boilerplate: Reverted changes unrelated to jQuery r…
backflip Sep 16, 2018
35d133e
[Change] estatico-boilerplate: Reverted changes unrelatedto jQuery re…
backflip Sep 16, 2018
c36ee0c
[Fix] estatico-boilerplate: Expose module uuid instead of instance du…
backflip Sep 17, 2018
5f07f7c
[Chore] estatico-boilerplate: Removed outdated comment
backflip Sep 17, 2018
e6ba035
[Fix] estatico-boilerplate: Optimized usage of dom-delegate
backflip Sep 17, 2018
2113049
[Chore] estatico-qunit/estatico-svgsprite: Rewrote client-side code t…
backflip Sep 18, 2018
737f836
[Fix] estatico-boilerplate: Added missing polyfills for IE11
backflip Sep 18, 2018
0535fe5
Merged develop
backflip Sep 19, 2018
a6681ec
[Change] estatico-boilerplate: Moved fetch polyfill
backflip Sep 19, 2018
20d1c9e
[Change] estatico-eslint: Added default config, added babel-eslint as…
backflip Sep 19, 2018
ebc5fc2
[Chore] estatico-boilerplate: Fixed linting issues
backflip Sep 19, 2018
925e7ec
Merged develop
backflip Sep 19, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions packages/estatico-boilerplate/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
module.exports = {
extends: 'airbnb-base',
rules: {
'import/no-extraneous-dependencies': 'off',
'import/no-unresolved': 'off',
'class-methods-use-this': 'off'
},
env: {
node: true,
browser: true,
},
extends: require.resolve('@unic/estatico-eslint/.eslintrc.js'),
globals: {
estatico: true,
Modernizr: true,
},
};
6 changes: 5 additions & 1 deletion packages/estatico-boilerplate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@
},
"dependencies": {
"bows": "^1.7.0",
"custom-event-polyfill": "^1.0.6",
"dom-delegate": "^2.2.0",
"highlight.js": "^9.12.0",
"jquery": "^3.3.1",
"lodash": "^4.17.10",
"merge-stream": "^1.0.1",
"nodelist-foreach-polyfill": "^1.2.0",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can think about using https://github.com/WebReflection/dom4. It includes these polyfills and some more. We normally load this in a separate entry file either in a sync way using document.write or in a ordered way async.

"normalize.css": "^8.0.0",
"raf-throttle": "^2.0.3",
"skip-link-focus": "^1.0.0"
"skip-link-focus": "^1.0.0",
"whatwg-fetch": "^3.0.0"
},
"engines": {
"node": ">=8"
Expand Down
48 changes: 23 additions & 25 deletions packages/estatico-boilerplate/src/assets/js/helpers/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
*
* @license APLv2
*/
import $ from 'jquery';
import namespace from './namespace';
import loadPolyfills from './polyfills';

/** Demo modules * */
import SkipLinks from '../../../demo/modules/skiplinks/skiplinks';
Expand All @@ -18,35 +18,36 @@ class App {

this.initEvents = [];

SkipLinks.init();

// Module registry - mapping module name (used in data-init) to module Class
this.modules = {};
this.modules.slideshow = SlideShow;
/* autoinsertmodule */ // eslint-disable-line
this.modules.skiplinks = SkipLinks;
/* autoinsertmodule */ // eslint-disable-line

// expose initModule function
window[namespace].helpers.initModule = this.initModule;
}

start() {
async start() {
await loadPolyfills();

this.registerModules();
this.initModuleInitialiser();
}

initModule(moduleName, $node) {
initModule(moduleName, element) {
const Module = window[namespace].modules[moduleName].Class;
const metaData = $node.data(`${moduleName}-data`) || {};
const metaOptions = $node.data(`${moduleName}-options`) || {};
const moduleInstance = new Module($node, metaData, metaOptions);
const metaData = element.dataset[`${moduleName}Data`] || {};
const metaOptions = element.dataset[`${moduleName}Options`] || {};
const moduleInstance = new Module(element, metaData, metaOptions);

window[namespace].modules[moduleName].instances[moduleInstance.uuid] = moduleInstance;
$node.data(`${moduleName}Instance`, moduleInstance);
element.dataset[`${moduleName}Instance`] = moduleInstance.uuid; // eslint-disable-line no-param-reassign
}

registerModules() {
$('[data-init]').each((key, element) => {
const modules = $(element).data('init').split(' ');
[].slice.call(document.querySelectorAll('[data-init]')).forEach((element) => {
backflip marked this conversation as resolved.
Show resolved Hide resolved
const modules = element.dataset.init.split(' ');

modules.forEach((moduleName) => {
this.registerModule(moduleName);
Expand Down Expand Up @@ -76,25 +77,23 @@ class App {
return window[namespace].modules[moduleName];
}

isInitialised($element, moduleName) {
// jQuery 3 does not allow kebab-case in data() when retrieving whole data object https://jquery.com/upgrade-guide/3.0/#breaking-change-data-names-containing-dashes
return $element.data(`${moduleName}Instance`);
isInitialised(element, moduleName) {
return element.dataset[`${moduleName}Instance`];
}

isInitEvent(eventType, moduleName) {
return window[namespace].modules[moduleName].initEvents.indexOf(eventType) !== -1;
}

initModules(event) {
$('[data-init]').each((key, element) => {
const $element = $(element);
const modules = $element.data('init').split(' ');
[].slice.call(document.querySelectorAll('[data-init]')).forEach((element) => {
backflip marked this conversation as resolved.
Show resolved Hide resolved
const modules = element.dataset.init.split(' ');

modules.forEach((moduleName) => {
if (this.isRegistered(moduleName)
&& !this.isInitialised($element, moduleName)
&& this.isInitEvent(event.type, moduleName)) {
this.initModule(moduleName, $element);
&& !this.isInitialised(element, moduleName)
&& this.isInitEvent(event.type, moduleName)) {
this.initModule(moduleName, element);
}
});
});
Expand All @@ -105,10 +104,9 @@ class App {
return;
}

// jQuery 3 does not support `ready` event in $(document).on() https://jquery.com/upgrade-guide/3.0/#breaking-change-on-quot-ready-quot-fn-removed
// But lets sent 'ready' information to modules initialising on that event
$(this.initModules.bind(this, { type: 'ready' }));
$(document).on(this.initEvents.join(' '), this.initModules.bind(this));
this.initEvents.forEach((event) => {
document.addEventListener(event, this.initModules.bind(this), false);
});
}
}

Expand Down
58 changes: 34 additions & 24 deletions packages/estatico-boilerplate/src/assets/js/helpers/events.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import $ from 'jquery';
import { Delegate } from 'dom-delegate';
import debounce from 'lodash/debounce';
import throttle from 'raf-throttle';
import namespace from './namespace';

/**
* Adds debounced and throttled global resize and scroll events and generates public methods
Expand All @@ -13,15 +12,13 @@ import namespace from './namespace';
* @example
* // Listen to debounced scroll event:
* import WindowEventListener from './events';
* WindowEventListener.addDebouncedScrollListener((originalEvent, event) => {
* this.log(event, originalEvent);
* WindowEventListener.addDebouncedScrollListener((event) => {
* this.log(event);
* });
*/

class WindowEventListener {
constructor() {
this.$window = $(window);

const events = {
resize: {
interval: 50,
Expand All @@ -31,12 +28,26 @@ class WindowEventListener {
},
};

this.eventDelegate = new Delegate(document);
this.eventHandlers = {};

for (const eventName of Object.keys(events)) { // eslint-disable-line no-restricted-syntax
this.registerDebouncedEvent(eventName, events[eventName]);
this.registerThrottledEvent(eventName, events[eventName]);
}
}

/**
* Dispatch custom event on document
* @param {String} eventName
* @param {Object} data
*/
dispatch(eventName, data) {
this.eventDelegate.rootElement.dispatchEvent(new CustomEvent(eventName, {
detail: data,
}));
}

/**
* Window event has only one debounced handler.
* Achieved by triggering another fake event, which is the one we subscribe to
Expand All @@ -45,20 +56,18 @@ class WindowEventListener {
* @private
*/
registerDebouncedEvent(eventName, config) {
const debouncedEventName = `debounced${eventName}.${namespace}`;
const methodName = eventName.charAt(0).toUpperCase() + eventName.slice(1);
const debouncedEventName = `debounced${methodName}`;

this.$window.on(eventName, debounce((event) => {
$(document).triggerHandler(debouncedEventName, event);
}, config.interval));
window.addEventListener(eventName, debounce((event) => {
this.dispatch(debouncedEventName, {
originalEvent: event,
});
}, config.interval), false);

// adds a public shorthand method, e.g. addResizeListener to the WindowEventListener class
this[`addDebounced${methodName}Listener`] = this.addEventListener.bind(this, debouncedEventName);
this[`removeDebounced${methodName}Listener`] = this.removeEventListener.bind(this, debouncedEventName);

// Save to global namespace
$.extend(true, window[namespace], { events: {} });
window[namespace].events[debouncedEventName.split('.')[0]] = debouncedEventName;
}

/**
Expand All @@ -68,20 +77,18 @@ class WindowEventListener {
* @private
*/
registerThrottledEvent(eventName) {
const throttledEventName = `throttled${eventName}.${namespace}`;
const methodName = eventName.charAt(0).toUpperCase() + eventName.slice(1);
const throttledEventName = `throttled${methodName}`;

this.$window.on(eventName, throttle((event) => {
$(document).triggerHandler(throttledEventName, event);
window.addEventListener(eventName, throttle((event) => {
this.dispatch(throttledEventName, {
originalEvent: event,
});
}));

// adds a public shorthand method, e.g. addResizeListener to the WindowEventListener class
this[`addThrottled${methodName}Listener`] = this.addEventListener.bind(this, throttledEventName);
this[`removeThrottled${methodName}Listener`] = this.removeEventListener.bind(this, throttledEventName);

// Save to global namespace
$.extend(true, window[namespace], { events: {} });
window[namespace].events[throttledEventName.split('.')[0]] = throttledEventName;
}

/**
Expand All @@ -95,7 +102,10 @@ class WindowEventListener {
addEventListener(eventName, callback, uuid) {
const name = uuid ? `${eventName}.${uuid}` : eventName;

$(document).on(name, callback);
// Keep track of handler
this.eventHandlers[name] = callback;

this.eventDelegate.on(eventName, callback);
}

/**
Expand All @@ -108,9 +118,9 @@ class WindowEventListener {
removeEventListener(eventName, uuid) {
const name = uuid ? `${eventName}.${uuid}` : eventName;

$(document).off(name);
this.eventDelegate.off(eventName, this.eventHandlers[name]);
}
}

// Exports an INSTANCE
// Export default instance
export default new WindowEventListener();
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Helper {
}
}

// Deep extend (before $.extend is available)
// Deep extend
extend(destination, source) {
let property;

Expand Down
60 changes: 36 additions & 24 deletions packages/estatico-boilerplate/src/assets/js/helpers/mediaqueries.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* import MediaQuery from '../../../assets/js/modules/mediaqueries';
*
* // Listen to custom (debounced) event to react to viewport changes:
* MediaQuery.addMQChangeListener(function(event, prevBreakpoint, currentBreakpoint) {
* console.log(prevBreakpoint); // { name: "small", value: "768px" }
* console.log(parseInt(prevBreakpoint.value)); // "768"
* MediaQuery.addMQChangeListener((event) => {
* console.log(event.detail.prevBreakpoint); // { name: "small", value: "768px" }
* console.log(parseInt(event.detail.prevBreakpoint.value)); // "768"
* });
*
* // Check the current viewport against a specific breakpoint:
Expand All @@ -24,45 +24,57 @@
* }
*/

import $ from 'jquery';
import namespace from './namespace';
import { Delegate } from 'dom-delegate';
import WindowEventListener from './events';

class MediaQuery {
constructor() {
this.$document = $(document);
this.eventDelegate = new Delegate(document);
this.eventHandlers = {};
this.customEventName = 'mq';

this.$head = this.$document.find('head');
this.$title = this.$head.find('title');
this.ui = {
all: document.head,
current: document.querySelector('title'),
};

this.breakpointsString = this.$head.css('font-family');
this.currentBreakpointString = this.$title.css('font-family');
const breakpointsString = window.getComputedStyle(this.ui.all).getPropertyValue('font-family');
const currentBreakpointString = this.getCurrentBreakpointString();

this.breakpoints = this.parseCssProperty(this.breakpointsString);
this.currentBreakpoint = this.parseCssProperty(this.currentBreakpointString);
this.breakpoints = this.parseCssProperty(breakpointsString);
this.currentBreakpoint = this.parseCssProperty(currentBreakpointString);

// Save to global namespace
$.extend(true, window[namespace], { events: {} });
window[namespace].events.mq = `mq.${namespace}`;

this.$document.on('debouncedresize.window[namespace].mq', () => {
const breakpoint = this.parseCssProperty(this.$title.css('font-family'));
WindowEventListener.addDebouncedResizeListener(() => {
const breakpoint = this.parseCssProperty(this.getCurrentBreakpointString());
const prevBreakpoint = this.currentBreakpoint;

if (breakpoint && breakpoint.name !== this.currentBreakpoint.name) {
this.currentBreakpoint = breakpoint;
this.$document.triggerHandler(window[namespace].events.mq, [prevBreakpoint, breakpoint]);

WindowEventListener.dispatch(this.customEventName, {
prevBreakpoint,
breakpoint,
});
}
});
}, this.customEventName);
}

addMQChangeListener(callback, uuid) {
this.$document.on(`${window[namespace].events.mq}.${uuid}`, (prevBreakpoint, breakpoint) => {
callback(prevBreakpoint, breakpoint);
});
this.eventHandlers[uuid] = callback;

this.eventDelegate.on(this.customEventName, callback);
}

removeMQChangeListener(uuid) {
this.eventDelegate.off(this.customEventName, this.eventHandlers[uuid]);
}

parseCssProperty(str) {
return $.parseJSON($.trim(str.replace(/^('|")|(\\)|('|")$/g, '')));
return JSON.parse(str.replace(/^('|")|(\\)|('|")$/g, '').trim());
}

getCurrentBreakpointString() {
return window.getComputedStyle(this.ui.current).getPropertyValue('font-family');
}

getBreakpointValue(breakpoint) {
Expand Down
Loading