UNPKG

simplestatemanager

Version:

SimpleStateManager is a library that allows you to enable and disable JavaScript based on the characteristics of the device.

171 lines (140 loc) 4.57 kB
import { fireAllMethodsInArray, makeID, } from './utils'; const configOptions = []; let stateChangeMethod = () => { }; export default class State { constructor(options) { this.id = options.id || makeID(); this.query = options.query || 'all'; const defaultOptions = { onEnter: [], onLeave: [], onResize: [], onFirstRun: [], }; // Merge options with defaults to make the state this.options = Object.assign({}, defaultOptions, options); // Migrate methods into an array, this is to enable future functionality of adding extra methods to an existing state if (typeof this.options.onEnter === 'function') { this.options.onEnter = [this.options.onEnter]; } if (typeof this.options.onLeave === 'function') { this.options.onLeave = [this.options.onLeave]; } if (typeof this.options.onResize === 'function') { this.options.onResize = [this.options.onResize]; } if (typeof this.options.onFirstRun === 'function') { this.options.onFirstRun = [this.options.onFirstRun]; } // Test the one time tests first, if the test is invalid we wont create the config option if (this.testConfigOptions('once') === false) { this.valid = false; return false; } this.valid = true; this.active = false; this.init(); } init() { this.test = window.matchMedia(this.query); if (this.test.matches && this.testConfigOptions('match')) { this.enterState(); } this.listener = (test) => { let changed = false; if (test.matches) { if (this.testConfigOptions('match')) { this.enterState(); changed = true; } } else { this.leaveState(); changed = true; } if (changed) { stateChangeMethod(); } }; this.test.addListener(this.listener); } // Handle entering a state enterState() { fireAllMethodsInArray(this.options.onFirstRun, this.eventData('firstRun')); fireAllMethodsInArray(this.options.onEnter, this.eventData('enter')); this.options.onFirstRun = []; this.active = true; } // Handle leaving a state leaveState() { fireAllMethodsInArray(this.options.onLeave, this.eventData('leave')); this.active = false; } // Handle the user resizing the browser resizeState() { if (this.testConfigOptions('resize')) { fireAllMethodsInArray(this.options.onResize, this.eventData('resize')); } } // When the StateManager removes a state we want to remove the event listener destroy() { this.test.removeListener(this.listener); } attachCallback(type, callback, runIfActive) { switch (type) { case 'enter': this.options.onEnter.push(callback); break; case 'leave': this.options.onLeave.push(callback); break; case 'resize': this.options.onResize.push(callback); break; default: break; } if (type === 'enter' && runIfActive && this.active) { callback(this.eventData(type)); } } testConfigOptions(when) { let test = true; configOptions.forEach((configOption) => { if (typeof this.options[configOption.name] !== 'undefined') { if (configOption.when === when && configOption.test.bind(this)() === false) { test = false; } } }); return test; } eventData(eventType) { return { eventType, state: this, }; } static addConfigOption(configOption) { configOptions.push(configOption); } static getConfigOptions() { return configOptions; } static removeConfigOption(name) { configOptions.forEach((item, index) => { if (item.name === name) { configOptions.splice(index, 1); } }); } static setStateChangeMethod(func) { if (typeof func === 'function') { stateChangeMethod = func; } else { throw new Error('Not a function'); } } }