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

#22 Add AuthorVH #136

Merged
merged 4 commits into from
Aug 17, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,51 +1,8 @@
window.dx = window.dx || {};
window.dx.author = { watch: { functions: [] } };
// Ignore for code coverage
/* istanbul ignore file */

window.dx.author.watch.registerFunction = (func) => {
window.dx.author.watch.functions.push(func);
};

const TAG_SCRIPT = 'SCRIPT';
const WATCH_CONFIG = {
childList: true,
subtree: true,
};

/**
* Watch for Author mutations and run functions when they meet node type criteria.
*
* @param {Array} apps The functions or classes to instantiate when a mutation occurs
* @param {DOMElment} parent The top level parent to start the observation
*/
const watch = (document) => {
const parentToWatch = document.querySelector('body');

const callback = (mutationsList) => {
mutationsList.forEach((mutation) => {
// Attempt to cut down on noise from all mutations.
// An AEM component mutation will have only one added node. No more. No less.
if (window.dx.author.watch.functions.length > 0 && mutation.addedNodes.length === 1) {
const addedNode = mutation.addedNodes[0];
if (addedNode.nodeType === 1 && addedNode.tagName !== TAG_SCRIPT) {
// Loop through each function and instantiate
// it with the added node.
window.dx.author.watch.functions.forEach((app) => {
app(addedNode);
});
}
}
});
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);
observer.observe(parentToWatch, WATCH_CONFIG);
};

const authorWatch = (document) => {
if (typeof CQ !== 'undefined' && document) {
watch(document);
}
};
import { initAuthorVh } from './utils/authorVh';
import authorWatch from './utils/authorWatch';

authorWatch(document);
initAuthorVh(document);
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!-- 0 Mobile Only -->
<div data-author-mobile-vh="20" class="has-AuthorVh"></div>
<!-- 1 Tablet -->
<div data-author-mobile-vh="20" data-author-tablet-vh="40" class="has-AuthorVh"></div>
<!-- 2 Desktop -->
<div data-author-mobile-vh="20" data-author-tablet-vh="40" data-author-desktop-vh="60" class="has-AuthorVh"></div>
<!-- 3 Bad Data -->
<div data-author-mobile-vh="asdf" class="has-AuthorVh bad-element"></div>
<!-- No Data -->
<div class="dexter-is-awesome"></div>

<!-- With item vhs set-->
<!-- 4 Mobile Only -->
<div data-author-mobile-vh="20" data-author-mobile-items-vh="100" class="has-AuthorVh"></div>
<!-- 5 Tablet -->
<div data-author-mobile-vh="20" data-author-mobile-items-vh="20,,40" data-author-tablet-vh="40" data-author-tablet-items-vh="0,15,90" class="has-AuthorVh"></div>
<!-- 6 Desktop -->
<div data-author-mobile-vh="20" data-author-mobile-items-vh=",,99,30"
data-author-tablet-vh="40" data-author-tablet-items-vh="0,15,,40"
data-author-desktop-vh="60" data-author-desktop-items-vh="10" class="has-AuthorVh">
<div id="i1">i1</div>
<div id="i2">i2</div>
<div id="i3">i3</div>
<div id="i4">i4</div>
</div>
<!-- 7 Bad Data -->
<div data-author-mobile-vh="asdf" data-author-tablet-items-vh="asdf" class="has-AuthorVh bad-element"></div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import vhHtml from '../__mocks__/vh.html';
import {
initAuthorVh,
findAuthorVhElements,
getEditorHeight,
setVh,
getInitialWidth,
getVhAsPx,
getBreakpointVh,
} from '../authorVh';

// Define our innerWidth
Object.defineProperties(window, {
innerWidth: { value: 300, configurable: true, writable: true },
innerHeight: { value: 720 },
});

document.body.innerHTML = vhHtml;

let elements;
let editorHeight;

beforeAll(() => {
elements = findAuthorVhElements(document);
});

describe('count elements with VH', () => {
test('four total elements', () => {
expect(window.innerWidth).toEqual(300);
expect(elements).toHaveLength(8);
});
});

describe('get editor height', () => {
test('height is height minus AEM toolbar', () => {
editorHeight = getEditorHeight();
expect(editorHeight).toEqual(610);
});
});

describe('setting VH', () => {
test('VH is correctly set on first element', () => {
const mobileElement = setVh(elements[0], 'mobile', editorHeight);
expect(mobileElement.style.minHeight).toEqual('122px');
});
test('bad data is not set on element', () => {
const badElement = document.querySelector('.bad-element');
expect(badElement.style.minHeight).toBeFalsy();
});
});

describe('get initial width', () => {
test('width should be mobile', () => {
const initialWidth = getInitialWidth();
expect(initialWidth).toEqual('mobile');
});

test('width should be tablet', () => {
Object.defineProperties(window, {
innerWidth: { value: 768, configurable: true, writable: true },
});
const initialWidth = getInitialWidth();
expect(initialWidth).toEqual('tablet');
});
test('width should be desktop', () => {
Object.defineProperties(window, {
innerWidth: { value: 1366, configurable: true, writable: true },
});
const initialWidth = getInitialWidth();
expect(initialWidth).toEqual('desktop');
});
});

describe('get vh to px', () => {
test('vh should not convert to px', () => {
const pxValue = getVhAsPx(900, 'foo');
expect(pxValue).toBeNull();
});
test('vh should convert to px', () => {
const pxValue = getVhAsPx(900, 66);
expect(pxValue).toEqual(594);
});
});

describe('get breakpoint vh as px', () => {
test('breakpoint vh should be mobile', () => {
const el = elements[2];
const pxValueMobile = getBreakpointVh('mobile', window.innerHeight, el.dataset);
expect(pxValueMobile.flexVh).toEqual(144);
});

test('breakpoint vh should be tablet', () => {
const el = elements[2];
const pxValueMobile = getBreakpointVh('tablet', window.innerHeight, el.dataset);
expect(pxValueMobile.flexVh).toEqual(288);
});

test('breakpoint vh should be desktop', () => {
const el = elements[2];
const pxValueMobile = getBreakpointVh('desktop', window.innerHeight, el.dataset);
expect(pxValueMobile.flexVh).toEqual(432);
});
});

describe('breakpoint vh with items defined', () => {
test('mobile only', () => {
const el = elements[4];
const { flexVh, itemVhs } = getBreakpointVh('mobile', window.innerHeight, el.dataset);
expect(flexVh).toEqual(144);
expect(itemVhs).toEqual([720]);
});

test('tablet override', () => {
const el = elements[5];
const { flexVh, itemVhs } = getBreakpointVh('mobile', window.innerHeight, el.dataset);
expect(flexVh).toEqual(144);
expect(itemVhs).toEqual([144, null, 288]);

const { flexVh: flexVh1, itemVhs: itemVhs1 } = getBreakpointVh(
'tablet',
window.innerHeight,
el.dataset
);
expect(flexVh1).toEqual(288);
expect(itemVhs1).toEqual([null, 108, 648]);
});

test('desktop override + item inheritance', () => {
const el = elements[6];

const item1 = el.querySelector('#i1');
const item2 = el.querySelector('#i2');
const item3 = el.querySelector('#i3');
const item4 = el.querySelector('#i4');

setVh(el, 'mobile', window.innerHeight, el.dataset);
expect(item1.style.minHeight).toBe('');
expect(item2.style.minHeight).toBe('');
expect(item3.style.minHeight).toBe('712.8px');
expect(item4.style.minHeight).toBe('216px');

setVh(el, 'tablet', window.innerHeight, el.dataset);
expect(item1.style.minHeight).toBe('');
expect(item2.style.minHeight).toBe('108px');
expect(item3.style.minHeight).toBe('712.8px');
expect(item4.style.minHeight).toBe('288px');

setVh(el, 'desktop', window.innerHeight, el.dataset);
expect(item1.style.minHeight).toBe('72px');
expect(item2.style.minHeight).toBe('108px');
expect(item3.style.minHeight).toBe('712.8px');
expect(item4.style.minHeight).toBe('288px');
});
});

describe('initAuthorVh', () => {
test('four total elements', () => {
const addListener = jest.fn();
global.matchMedia = () => ({ addListener });
initAuthorVh(document);
expect(addListener).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ window.MutationObserver = SimulateMutationObserver;
window.CQ = {};

// use require as import is hoisted
require('../app');
const authorWatch = require('../authorWatch.js').default;
authorWatch(document);

describe('authorWatch', () => {
beforeEach(() => {
Expand Down
Loading