From eaab1def7af7d7e1ab32ff69d043b46e2815ca22 Mon Sep 17 00:00:00 2001 From: fat Date: Wed, 13 May 2015 14:46:50 -0700 Subject: add simple type checker implementation --- js/src/carousel.js | 16 +++++++++++++++- js/src/collapse.js | 14 +++++++++++++- js/src/modal.js | 15 ++++++++++++++- js/src/popover.js | 8 ++++++++ js/src/scrollspy.js | 8 ++++++++ js/src/tab.js | 4 ---- js/src/tooltip.js | 25 ++++++++++++++++++++++++- js/src/util.js | 28 ++++++++++++++++++++++++++++ 8 files changed, 110 insertions(+), 8 deletions(-) (limited to 'js/src') diff --git a/js/src/carousel.js b/js/src/carousel.js index a4b6da298..c11f0a599 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -33,6 +33,14 @@ const Carousel = (($) => { wrap : true } + const DefaultType = { + interval : '(number|boolean)', + keyboard : 'boolean', + slide : '(boolean|string)', + pause : '(string|boolean)', + wrap : 'boolean' + } + const Direction = { NEXT : 'next', PREVIOUS : 'prev' @@ -84,7 +92,7 @@ const Carousel = (($) => { this._isPaused = false this._isSliding = false - this._config = config + this._config = this._getConfig(config) this._element = $(element)[0] this._indicatorsElement = $(this._element).find(Selector.INDICATORS)[0] @@ -193,6 +201,12 @@ const Carousel = (($) => { // private + _getConfig(config) { + config = $.extend({}, Default, config) + Util.typeCheckConfig(NAME, config, DefaultType) + return config + } + _addEventListeners() { if (this._config.keyboard) { $(this._element) diff --git a/js/src/collapse.js b/js/src/collapse.js index ded623448..6a5fcd854 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -30,6 +30,11 @@ const Collapse = (($) => { parent : null } + const DefaultType = { + toggle : 'boolean', + parent : '(string|null)' + } + const Event = { SHOW : `show${EVENT_KEY}`, SHOWN : `shown${EVENT_KEY}`, @@ -67,7 +72,7 @@ const Collapse = (($) => { constructor(element, config) { this._isTransitioning = false this._element = element - this._config = $.extend({}, Default, config) + this._config = this._getConfig(config) this._triggerArray = $.makeArray($( `[data-toggle="collapse"][href="#${element.id}"],` + `[data-toggle="collapse"][data-target="#${element.id}"]` @@ -259,6 +264,13 @@ const Collapse = (($) => { // private + _getConfig(config) { + config = $.extend({}, Default, config) + config.toggle = !!config.toggle // coerce string values + Util.typeCheckConfig(NAME, config, DefaultType) + return config + } + _getDimension() { let hasWidth = $(this._element).hasClass(Dimension.WIDTH) return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT diff --git a/js/src/modal.js b/js/src/modal.js index 084c4ec3a..2ca603b23 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -33,6 +33,13 @@ const Modal = (($) => { show : true } + const DefaultType = { + backdrop : '(boolean|string)', + keyboard : 'boolean', + focus : 'boolean', + show : 'boolean' + } + const Event = { HIDE   : `hide${EVENT_KEY}`, HIDDEN   : `hidden${EVENT_KEY}`, @@ -71,7 +78,7 @@ const Modal = (($) => { class Modal { constructor(element, config) { - this._config = config + this._config = this._getConfig(config) this._element = element this._dialog = $(element).find(Selector.DIALOG)[0] this._backdrop = null @@ -198,6 +205,12 @@ const Modal = (($) => { // private + _getConfig(config) { + config = $.extend({}, Default, config) + Util.typeCheckConfig(NAME, config, DefaultType) + return config + } + _showElement(relatedTarget) { let transition = Util.supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE) diff --git a/js/src/popover.js b/js/src/popover.js index eab4c7e63..31c7a3ae1 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -33,6 +33,10 @@ const Popover = (($) => { + '
' }) + const DefaultType = $.extend({}, Tooltip.DefaultType, { + content : '(string|function)' + }) + const ClassName = { FADE : 'fade', IN : 'in' @@ -93,6 +97,10 @@ const Popover = (($) => { return EVENT_KEY } + static get DefaultType() { + return DefaultType + } + // overrides diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index bb639f91b..a407511f6 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -30,6 +30,12 @@ const ScrollSpy = (($) => { target : '' } + const DefaultType = { + offset : 'number', + method : 'string', + target : '(string|element)' + } + const Event = { ACTIVATE : `activate${EVENT_KEY}`, SCROLL : `scroll${EVENT_KEY}`, @@ -164,6 +170,8 @@ const ScrollSpy = (($) => { config.target = `#${id}` } + Util.typeCheckConfig(NAME, config, DefaultType) + return config } diff --git a/js/src/tab.js b/js/src/tab.js index 61c062d89..4d8d7dec8 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -72,10 +72,6 @@ const Tab = (($) => { return VERSION } - static get Default() { - return Default - } - // public diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 42639895e..5d62e154a 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -37,7 +37,20 @@ const Tooltip = (($) => { selector : false, placement : 'top', offset : '0 0', - constraints : null + constraints : [] + } + + const DefaultType = { + animation : 'boolean', + template : 'string', + title : '(string|function)', + trigger : 'string', + delay : '(number|object)', + html : 'boolean', + selector : '(string|boolean)', + placement : '(string|function)', + offset : 'string', + constraints : 'array' } const AttachmentMap = { @@ -141,6 +154,10 @@ const Tooltip = (($) => { return EVENT_KEY } + static get DefaultType() { + return DefaultType + } + // public @@ -544,6 +561,12 @@ const Tooltip = (($) => { } } + Util.typeCheckConfig( + NAME, + config, + this.constructor.DefaultType + ) + return config } diff --git a/js/src/util.js b/js/src/util.js index c9ffbe555..86bea6578 100644 --- a/js/src/util.js +++ b/js/src/util.js @@ -23,6 +23,15 @@ const Util = (($) => { transition : 'transitionend' } + // shoutout AngusCroll (https://goo.gl/pxwQGp) + function toType(obj) { + return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase() + } + + function isElement(obj) { + return (obj[0] || obj).nodeType; + } + function getSpecialTransitionEndEvent() { return { bindType: transition.end, @@ -115,6 +124,25 @@ const Util = (($) => { supportsTransitionEnd() { return !!transition + }, + + typeCheckConfig(componentName, config, configTypes) { + + for (let property in configTypes) { + let expectedTypes = configTypes[property] + let value = config[property] + let valueType + + if (value && isElement(value)) valueType = 'element' + else valueType = toType(value) + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new Error( + `${componentName.toUpperCase()}: ` + + `Option "${property}" provided type "${valueType}" ` + + `but expected type "${expectedTypes}".`) + } + } } } -- cgit v1.2.3