1
0
mirror of https://github.com/webslides/WebSlides.git synced 2025-08-20 03:41:38 +02:00

Testing setup and first DOM tests

This commit is contained in:
Luis
2017-04-18 20:06:38 +02:00
parent 728e665fc9
commit 54e83e3a20
5 changed files with 256 additions and 2 deletions

3
.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["es2015"]
}

View File

@@ -28,11 +28,14 @@
},
"homepage": "https://github.com/webslides/webslides#readme",
"devDependencies": {
"ava": "^0.19.1",
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
"babel-loader": "^6.4.1",
"babel-preset-env": "^1.4.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"browser-env": "^2.0.30",
"eslint": "^3.19.0",
"eslint-loader": "^1.7.1",
"npm-run-all": "^4.0.2",
@@ -46,7 +49,8 @@
"build": "npm-run-all --parallel build:*",
"build:main": "webpack",
"build:main.min": "webpack --output-filename [name].min.js -p",
"dev": "webpack-dev-server"
"dev": "webpack-dev-server",
"test": "ava test/*.js"
},
"babel": {
"presets": [
@@ -54,8 +58,23 @@
"es2015",
{
"modules": false
}
},
"@ava/stage-4",
"@ava/transform-test-files"
]
]
},
"ava": {
"babel": {
"presets": [
"es2015",
"stage-0",
"react"
]
},
"require": [
"babel-register",
"./test/helpers/setup-browser-env.js"
]
}
}

190
src/js/plugins/zoom.js Normal file
View File

@@ -0,0 +1,190 @@
import DOM from '../utils/dom';
import Keys from '../utils/keys';
import Slide from '../modules/slide';
const CLASSES = {
ZOOM: 'grid',
DIV: 'column',
WRAP: 'wrap-zoom'
};
const ID = 'webslides-zoomed';
/**
* Zoom plugin.
*/
export default class Zoom {
/**
* @param {WebSlides} wsInstance The WebSlides instance
* @constructor
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
/**
* @type {WebSlides}
* @private
*/
this.zws_ = {};
/**
* @type {boolean}
* @private
*/
this.isZoomed_ = false;
this.preBuildZoom_();
document.body.addEventListener('keydown', this.onKeyDown.bind(this));
window.addEventListener('resize', this.onWindowResize.bind(this));
}
/**
* On key down handler. Will decide if Zoom in or out
* @param {Event} event Key down event
*/
onKeyDown(event) {
if ( !this.isZoomed_ && Keys.MINUS.includes( event.which ) ) {
this.zoomIn();
} else if ( this.isZoomed_ && Keys.PLUS.includes( event.which ) ) {
this.zoomOut();
}
}
/**
* Prepare zoom structure, scales the slides and uses a grid layout
* to show them
*/
preBuildZoom_() {
// Clone #webslides element
this.zws_.el = this.ws_.el.cloneNode();
this.zws_.el.id = ID;
this.zws_.el.className = CLASSES.ZOOM;
// Clone the slides
this.zws_.slides = [].map.call(this.ws_.slides,
(slide, i) => {
const s_ = slide.el.cloneNode(true);
this.zws_.el.appendChild(s_);
return new Slide(s_, i);
});
DOM.hide(this.zws_.el);
DOM.after(this.zws_.el, this.ws_.el);
// Creates the container for each slide
this.zws_.slides.forEach( elem => this.createSlideBlock_(elem));
}
/**
* Creates a block structure around the slide
* @param {Element} elem slide element
*/
createSlideBlock_(elem) {
// Wraps the slide around a container
const wrap = DOM.wrap(elem.el, 'div');
wrap.className = CLASSES.WRAP;
// Slide container, need due to flexbox styles
const div = DOM.wrap(wrap, 'div');
div.className = CLASSES.DIV;
// Adding some layer for controling click events
const divLayer = document.createElement('div');
divLayer.className = 'zoom-layer';
divLayer.addEventListener('click', e => {
this.zoomOut();
this.ws_.goToSlide(elem.i);
});
wrap.appendChild(divLayer);
// Slide number
const slideNumber = document.createElement('span');
slideNumber.className = 'slide-number';
slideNumber.textContent = `${elem.i+1}`;
div.appendChild(slideNumber);
// Zoom out when click in slide "border"
div.addEventListener('click', this.ws_.toggleZoom);
this.setSizes_(div, wrap, elem);
}
/**
* Sets layers size
* @param {Element} div flexbox element
* @param {Element} wrap wrapping element
* @param {Element} elem slide element
*/
setSizes_(div, wrap, elem) {
// Calculates the margins in relation to window width
const divCSS = window.getComputedStyle(div);
const marginW = DOM.parseSize(divCSS.paddingLeft)
+ DOM.parseSize(divCSS.paddingRight);
const marginH = DOM.parseSize(divCSS.paddingTop)
+ DOM.parseSize(divCSS.paddingBottom);
// Sets element size: window size - relative margins
const scale = divCSS.width.includes('%') ?
100 / DOM.parseSize(divCSS.width) :
window.innerWidth / DOM.parseSize(divCSS.width);
if (scale == 1) {
// If the scale is 100% means it is mobile
const wsW = this.ws_.el.clientWidth;
elem.el.style.width = `${(wsW - marginW) * 2}px`;
elem.el.style.height = `${(wsW - marginH) * 1.5}px`;
elem.el.style.minHeight = scale == 1? 'auto' : '';
// Because of flexbox, wrap height is required
wrap.style.height = `${(wsW - marginH) * 1.5 / 2}px`;
} else {
elem.el.style.width = `${window.innerWidth - marginW * scale}px`;
elem.el.style.height = `${window.innerHeight - marginH * scale}px`;
// Because of flexbox, wrap height is required
wrap.style.height = `${window.innerHeight / scale}px`;
}
}
/**
* Toggles zoom
*/
toggleZoom() {
if (this.isZoomed_) {
this.zoomOut();
} else {
this.zoomIn();
}
}
/**
* Zoom In the slider, scales the slides and uses a grid layout to show them
*/
zoomIn() {
DOM.hide(this.ws_.el);
DOM.show(this.zws_.el);
this.isZoomed_ = true;
document.body.style.overflow = 'auto';
}
/**
* Zoom Out the slider, remove scale from the slides
*/
zoomOut() {
DOM.hide(this.zws_.el);
DOM.show(this.ws_.el);
this.isZoomed_ = false;
document.body.style.overflow = '';
}
/**
* When windows resize it is necessary to recalculate layers sizes
* @param {Event} ev
*/
onWindowResize(ev) {
if (this.isZoomed_) this.zoomOut();
this.zws_.slides.forEach( elem => {
const wrap = elem.el.parentElement;
const div = wrap.parentElement;
this.setSizes_(div, wrap, elem);
});
}
}

40
test/dom.js Normal file
View File

@@ -0,0 +1,40 @@
import test from 'ava';
import DOM from '../src/js/utils/dom';
test('DOM.createNode', t => {
const div = DOM.createNode('div', 'my-id');
t.is(div.tagName, 'DIV');
t.is(div.id, 'my-id');
t.is(div.innerHTML, '');
});
test('DOM.once', t => {
const div = DOM.createNode('div');
DOM.once(div, 'click', () => div.classList.toggle('ok'));
div.click();
t.is(div.className, 'ok');
div.click();
t.is(div.className, 'ok');
});
test('DOM.hide', t => {
const div = DOM.createNode('div');
DOM.hide(div);
t.is(div.style.display, 'none');
});
test('DOM.show', t => {
const div = DOM.createNode('div');
DOM.hide(div);
DOM.show(div);
t.is(div.style.display, '');
});
test('DOM.fireEvent', t => {
const div = DOM.createNode('div');
div.addEventListener('toggle-class', () => div.classList.toggle('ok'));
DOM.fireEvent(div, 'toggle-class');
t.is(div.className, 'ok');
DOM.fireEvent(div, 'toggle-class');
t.is(div.className, '');
});

View File

@@ -0,0 +1,2 @@
import browserEnv from 'browser-env';
browserEnv();