Updated Layout to new JS Design pattern
Updated Layout component to use new JS design pattern as defined at: https://github.com/jasonmayes/wsk-component-design-patternmaster
parent
3d6939769f
commit
5a84e7eba8
|
@ -303,7 +303,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../third_party/wskComponentHandler.js"></script>
|
||||
<!-- build:js(app/styleguide/layout/) ../../scripts/main.min.js -->
|
||||
<script src="layout.js"></script>
|
||||
<script src="../textfield/textfield.js"></script>
|
||||
|
|
|
@ -1,85 +1,190 @@
|
|||
window.addEventListener('load', function() {
|
||||
/**
|
||||
* Class constructor for Layout WSK component.
|
||||
* Implements WSK component design pattern defined at:
|
||||
* https://github.com/jasonmayes/wsk-component-design-pattern
|
||||
* @param {HTMLElement} element The element that will be upgraded.
|
||||
*/
|
||||
function MaterialLayout(element) {
|
||||
'use strict';
|
||||
|
||||
var layouts = document.querySelectorAll('.wsk-js-layout');
|
||||
var MODE = {
|
||||
this.element_ = element;
|
||||
|
||||
// Initialize instance.
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store constants in one place so they can be updated easily.
|
||||
* @enum {string | number}
|
||||
* @private
|
||||
*/
|
||||
MaterialLayout.prototype.Constant_ = {
|
||||
MAX_WIDTH: '(max-width: 850px)'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Modes.
|
||||
* @enum {number}
|
||||
* @private
|
||||
*/
|
||||
MaterialLayout.prototype.Mode_ = {
|
||||
STANDARD: 0,
|
||||
SEAMED: 1,
|
||||
WATERFALL: 2,
|
||||
SCROLL: 3
|
||||
};
|
||||
|
||||
var SHADOW_CLASS = 'is-casting-shadow';
|
||||
var COMPACT_CLASS = 'is-compact';
|
||||
var SMALL_SCREEN_CLASS = 'is-small-screen';
|
||||
var DRAWER_OPEN_CLASS = 'is-visible';
|
||||
|
||||
var scrollHandlerGenerator = function(header, content) {
|
||||
/**
|
||||
* Store strings for class names defined by this component that are used in
|
||||
* JavaScript. This allows us to simply change it in one place should we
|
||||
* decide to modify at a later date.
|
||||
* @enum {string}
|
||||
* @private
|
||||
*/
|
||||
MaterialLayout.prototype.CssClasses_ = {
|
||||
/**
|
||||
* Class names should use camelCase and be prefixed with the word "material"
|
||||
* to minimize conflict with 3rd party systems.
|
||||
*/
|
||||
|
||||
// TODO: Upgrade classnames in HTML / CSS / JS to use material prefix to
|
||||
// reduce conflict and convert to camelCase for consistency.
|
||||
WSK_LAYOUT_HEADER: 'wsk-layout__header',
|
||||
|
||||
WSK_LAYOUT_DRAWER: 'wsk-layout__drawer',
|
||||
|
||||
WSK_LAYOUT_CONTENT: 'wsk-layout__content',
|
||||
|
||||
WSK_LAYOUT_HEADER_SEAMED: 'wsk-layout__header--seamed',
|
||||
|
||||
WSK_LAYOUT_HEADER_WATERFALL: 'wsk-layout__header--waterfall',
|
||||
|
||||
WSK_LAYOUT_HEADER_SCROLL: 'wsk-layout__header--scroll',
|
||||
|
||||
WSK_LAYOUT_DRAWER_BTN: 'wsk-layout__drawer-button',
|
||||
|
||||
WSK_LAYOUT_FIXED_HEADER: 'wsk-layout--fixed-header',
|
||||
|
||||
WSK_LAYOUT_OBFUSCATOR: 'wsk-layout__obfuscator',
|
||||
|
||||
SHADOW_CLASS: 'is-casting-shadow',
|
||||
|
||||
COMPACT_CLASS: 'is-compact',
|
||||
|
||||
SMALL_SCREEN_CLASS: 'is-small-screen',
|
||||
|
||||
DRAWER_OPEN_CLASS: 'is-visible'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generate a scroll handler function.
|
||||
* @param {Event} event The event that fired.
|
||||
* @private
|
||||
*/
|
||||
MaterialLayout.prototype.scrollHandlerGenerator_ = function(header, content) {
|
||||
'use strict';
|
||||
|
||||
return function() {
|
||||
if (content.scrollTop > 0) {
|
||||
header.classList.add(SHADOW_CLASS);
|
||||
header.classList.add(COMPACT_CLASS);
|
||||
header.classList.add(this.CssClasses_.SHADOW_CLASS);
|
||||
header.classList.add(this.CssClasses_.COMPACT_CLASS);
|
||||
} else {
|
||||
header.classList.remove(SHADOW_CLASS);
|
||||
header.classList.remove(COMPACT_CLASS);
|
||||
header.classList.remove(this.CssClasses_.SHADOW_CLASS);
|
||||
header.classList.remove(this.CssClasses_.COMPACT_CLASS);
|
||||
}
|
||||
};
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
var screenSizeHandlerGenerator = function(mediaQuery, layout, drawer) {
|
||||
|
||||
/**
|
||||
* Generate a screenSize handler function.
|
||||
* @param {Event} event The event that fired.
|
||||
* @private
|
||||
*/
|
||||
MaterialLayout.prototype.screenSizeHandlerGenerator_ =
|
||||
function(mediaQuery, layout, drawer) {
|
||||
'use strict';
|
||||
|
||||
return function() {
|
||||
if (mediaQuery.matches) {
|
||||
layout.classList.add(SMALL_SCREEN_CLASS);
|
||||
layout.classList.add(this.CssClasses_.SMALL_SCREEN_CLASS);
|
||||
}
|
||||
else {
|
||||
layout.classList.remove(SMALL_SCREEN_CLASS);
|
||||
layout.classList.remove(this.CssClasses_.SMALL_SCREEN_CLASS);
|
||||
// Collapse drawer (if any) when moving to a large screen size.
|
||||
if (drawer) {
|
||||
drawer.classList.remove(DRAWER_OPEN_CLASS);
|
||||
drawer.classList.remove(this.CssClasses_.DRAWER_OPEN_CLASS);
|
||||
}
|
||||
}
|
||||
};
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
var drawerToggleHandlerGenerator = function(drawer) {
|
||||
|
||||
/**
|
||||
* Generate a drawerToggle handler function.
|
||||
* @param {Event} event The event that fired.
|
||||
* @private
|
||||
*/
|
||||
MaterialLayout.prototype.drawerToggleHandlerGenerator_ =
|
||||
function(drawer) {
|
||||
'use strict';
|
||||
|
||||
return function() {
|
||||
drawer.classList.toggle(DRAWER_OPEN_CLASS);
|
||||
};
|
||||
drawer.classList.toggle(this.CssClasses_.DRAWER_OPEN_CLASS);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
for (var i = 0; i < layouts.length; i++) {
|
||||
var layout = layouts[i];
|
||||
var header = layout.querySelector('.wsk-layout__header');
|
||||
var drawer = layout.querySelector('.wsk-layout__drawer');
|
||||
var content = layout.querySelector('.wsk-layout__content');
|
||||
var mode = MODE.STANDARD;
|
||||
|
||||
/**
|
||||
* Initialize element.
|
||||
*/
|
||||
MaterialLayout.prototype.init = function() {
|
||||
'use strict';
|
||||
|
||||
if (this.element_) {
|
||||
var header = this.element_.querySelector('.' +
|
||||
this.CssClasses_.WSK_LAYOUT_HEADER);
|
||||
var drawer = this.element_.querySelector('.' +
|
||||
this.CssClasses_.WSK_LAYOUT_DRAWER);
|
||||
var content = this.element_.querySelector('.' +
|
||||
this.CssClasses_.WSK_LAYOUT_CONTENT);
|
||||
|
||||
var mode = this.Mode_.STANDARD;
|
||||
|
||||
// Keep an eye on screen size, and add/remove auxiliary class for styling
|
||||
// of small screens.
|
||||
var mediaQuery = window.matchMedia('(max-width: 850px)');
|
||||
var mediaQuery = window.matchMedia(this.Constant_.MAX_WIDTH);
|
||||
var screenSizeHandler =
|
||||
screenSizeHandlerGenerator(mediaQuery, layout, drawer);
|
||||
this.screenSizeHandlerGenerator_(mediaQuery, this.element_,
|
||||
drawer).bind(this);
|
||||
mediaQuery.addListener(screenSizeHandler);
|
||||
screenSizeHandler();
|
||||
|
||||
if (header) {
|
||||
if (header.classList.contains('wsk-layout__header--seamed')) {
|
||||
mode = MODE.SEAMED;
|
||||
} else if (header.classList.contains('wsk-layout__header--waterfall')) {
|
||||
mode = MODE.WATERFALL;
|
||||
} else if (layout.classList.contains('wsk-layout__header--scroll')) {
|
||||
mode = MODE.SCROLL;
|
||||
if (header.classList.contains(
|
||||
this.CssClasses_.WSK_LAYOUT_HEADER_SEAMED)) {
|
||||
mode = this.Mode_.SEAMED;
|
||||
} else if (header.classList.contains(
|
||||
this.CssClasses_.WSK_LAYOUT_HEADER_WATERFALL)) {
|
||||
mode = this.Mode_.WATERFALL;
|
||||
} else if (this.element_.classList.contains(
|
||||
this.CssClasses_.WSK_LAYOUT_HEADER_SCROLL)) {
|
||||
mode = this.Mode_.SCROLL;
|
||||
}
|
||||
|
||||
if (mode === MODE.STANDARD) {
|
||||
header.classList.add(SHADOW_CLASS);
|
||||
} else if (mode === MODE.SEAMED || mode === MODE.SCROLL) {
|
||||
header.classList.remove(SHADOW_CLASS);
|
||||
} else if (mode === MODE.WATERFALL) {
|
||||
if (mode === this.Mode_.STANDARD) {
|
||||
header.classList.add(this.CssClasses_.SHADOW_CLASS);
|
||||
} else if (mode === this.Mode_.SEAMED || mode === this.Mode_.SCROLL) {
|
||||
header.classList.remove(this.CssClasses_.SHADOW_CLASS);
|
||||
} else if (mode === this.Mode_.WATERFALL) {
|
||||
// Add and remove shadows depending on scroll position.
|
||||
// Also add/remove auxiliary class for styling of the compact version of
|
||||
// the header.
|
||||
var scrollHandler = scrollHandlerGenerator(header, content);
|
||||
var scrollHandler = this.scrollHandlerGenerator_(header,
|
||||
content).bind(this);
|
||||
content.addEventListener('scroll', scrollHandler);
|
||||
scrollHandler();
|
||||
}
|
||||
|
@ -88,23 +193,36 @@ window.addEventListener('load', function() {
|
|||
// Add drawer toggling button to our layout, if we have an openable drawer.
|
||||
if (drawer) {
|
||||
var drawerButton = document.createElement('div');
|
||||
drawerButton.classList.add('wsk-layout__drawer-button');
|
||||
var clickHandler = drawerToggleHandlerGenerator(drawer);
|
||||
drawerButton.classList.add(this.CssClasses_.WSK_LAYOUT_DRAWER_BTN);
|
||||
var clickHandler = this.drawerToggleHandlerGenerator_(drawer).bind(this);
|
||||
drawerButton.addEventListener('click', clickHandler);
|
||||
|
||||
// If we have a fixed header, add the button to the header rather than
|
||||
// the layout.
|
||||
if (layout.classList.contains('wsk-layout--fixed-header')) {
|
||||
if (this.element_.classList.contains(
|
||||
this.CssClasses_.WSK_LAYOUT_FIXED_HEADER)) {
|
||||
header.insertBefore(drawerButton, header.firstChild);
|
||||
} else {
|
||||
layout.insertBefore(drawerButton, content);
|
||||
this.element_.insertBefore(drawerButton, content);
|
||||
}
|
||||
|
||||
var obfuscator = document.createElement('div');
|
||||
obfuscator.classList.add('wsk-layout__obfuscator');
|
||||
layout.appendChild(obfuscator);
|
||||
obfuscator.classList.add(this.CssClasses_.WSK_LAYOUT_OBFUSCATOR);
|
||||
this.element_.appendChild(obfuscator);
|
||||
obfuscator.addEventListener('click', clickHandler);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
window.addEventListener('load', function() {
|
||||
'use strict';
|
||||
|
||||
// On document ready, the component registers itself. It can assume
|
||||
// componentHandler is available in the global scope.
|
||||
componentHandler.register({
|
||||
constructor: MaterialLayout,
|
||||
classAsString: 'MaterialLayout',
|
||||
cssClass: 'wsk-js-layout'
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue