<commit_before>module.exports = {
    metadata: {
        plugin: "gate",
        label: "Gate",
        role: "actor",
        family: "light",
        deviceTypes: ["microcontroller/microcontroller"],
        services: [{
            id: "open",
            label: "Open"
        }, {
            id: "close",
            label: "Close"
        }, {
            id: "openForTime",
            label: "Open for Time"
        }],
        state: [{
            id: "gateStatus",
            label: "Gate Status",
            type: {
                id: "Boolean"
            }
        }],
        configuration: [{
            label: "Pin",
            id: "pin",
            type: {
                family: "reference",
                id: "digitalInOutPin"
            },
            defaultValue: "12"
        }]
    },
    create: function () {
        return new Gate();
    }
};

var q = require('q');

/**
 *
 */
function Gate() {
    /**
     *
     */
    Gate.prototype.start = function () {
        var deferred = q.defer();

        this.state = {
            gateStatus: false
        };

        if (!this.isSimulated()) {
            try {
                var five = require("johnny-five");

                this.led = new five.Led(this.configuration.pin);

                this.logDebug("Gate initialized.");

                deferred.resolve();
            } catch (error) {
                this.device.node
                    .publishMessage("Cannot initialize "
                        + this.device.id + "/" + this.id
                        + ":" + error);

                deferred.reject(error);
            }
        }
        else {
            deferred.resolve();
        }

        return deferred.promise;
    };

    /**
     *
     */
    Gate.prototype.getState = function () {
        return this.state;
    };

    /**
     *
     */
    Gate.prototype.setState = function (state) {
        this.state.gateStatus = state.light;//TODO????########################################

        if (this.led) {
            if (this.state.gateStatus) {
                this.led.on();
            } else {
                this.led.stop().off();
            }
        }
    };

    /**
     *
     */
    Gate.prototype.open = function () {
        if (this.led) {
            this.led.on();
        }

        this.state = {
            gateStatus: true
        };

        setTimeout(function () {
            this.open();
            this.publishStateChange();

        }, 5000);

        this.publishStateChange();
    };

    Gate.prototype.openForTime = function () {
        if (this.led) {
            this.led.on();
        }

        this.state = {
            gateStatus: true
        };

        this.publishStateChange();
    };

    /**
     *
     */
    Gate.prototype.close = function () {
        if (this.led) {
            this.led.stop().off();
        }

        this.state = {
            gateStatus: false
        };

        this.publishStateChange();
    };
}<commit_msg>gate device<commit_after>module.exports = {
    metadata: {
        plugin: "gate",
        label: "Gate",
        role: "actor",
        family: "light",
        deviceTypes: ["microcontroller/microcontroller"],
        services: [{
            id: "open",
            label: "Open"
        }, {
            id: "close",
            label: "Close"
        }, {
            id: "openForTime",
            label: "Open for Time"
        }],
        state: [{
            id: "gateStatus",
            label: "Gate Status",
            type: {
                id: "Boolean"
            }
        }],
        configuration: [{
            label: "Pin",
            id: "pin",
            type: {
                family: "reference",
                id: "digitalInOutPin"
            },
            defaultValue: "12"
        }]
    },
    create: function () {
        return new Gate();
    }//
};

var q = require('q');

/**
 *
 */
function Gate() {
    /**
     *
     */
    Gate.prototype.start = function () {
        var deferred = q.defer();

        this.state = {
            gateStatus: false
        };

        if (!this.isSimulated()) {
            try {
                var five = require("johnny-five");

                this.led = new five.Led(this.configuration.pin);

                this.logDebug("Gate initialized.");

                deferred.resolve();
            } catch (error) {
                this.device.node
                    .publishMessage("Cannot initialize "
                        + this.device.id + "/" + this.id
                        + ":" + error);

                deferred.reject(error);
            }
        }
        else {
            deferred.resolve();
        }

        return deferred.promise;
    };

    /**
     *
     */
    Gate.prototype.getState = function () {
        return this.state;
    };

    /**
     *
     */
    Gate.prototype.setState = function (state) {
        this.state.gateStatus = state.light;//TODO????########################################

        if (this.led) {
            if (this.state.gateStatus) {
                this.led.on();
            } else {
                this.led.stop().off();
            }
        }
    };

    /**
     *
     */
    Gate.prototype.open = function () {
        if (this.led) {
            this.led.on();
        }

        this.state = {
            gateStatus: true
        };

        setTimeout(function () {
            this.open();
            this.publishStateChange();

        }, 5000);

        this.publishStateChange();
    };

    Gate.prototype.openForTime = function () {
        if (this.led) {
            this.led.on();
        }

        this.state = {
            gateStatus: true
        };

        this.publishStateChange();
    };

    /**
     *
     */
    Gate.prototype.close = function () {
        if (this.led) {
            this.led.stop().off();
        }

        this.state = {
            gateStatus: false
        };

        this.publishStateChange();
    };
}<|endoftext|>


<commit_before>import { checkPropTypes } from './check-props';
import { getDisplayName } from './devtools/custom';
import { options, Component } from 'preact';
import { ELEMENT_NODE, DOCUMENT_NODE, DOCUMENT_FRAGMENT_NODE } from './constants';

function getClosestDomNodeParent(parent) {
	if (!parent) return {};
	if (typeof parent.type === 'function') {
		return getClosestDomNodeParent(parent._parent);
	}
	return parent;
}

export function initDebug() {
	/* eslint-disable no-console */
	let oldBeforeDiff = options._diff;
	let oldDiffed = options.diffed;
	let oldVnode = options.vnode;
	let oldCatchError = options._catchError;
	let oldRoot = options._root;
	let oldHook = options._hook;
	const warnedComponents = { useEffect: {}, useLayoutEffect: {}, lazyPropTypes: {} };

	options._catchError = (error, vnode, oldVNode) => {
		let component = vnode && vnode._component;
		if (component && typeof error.then === 'function') {
			const promise = error;
			error = new Error('Missing Suspense. The throwing component was: ' + getDisplayName(vnode));

			let parent = vnode;
			for (; parent; parent = parent._parent) {
				if (parent._component && parent._component._childDidSuspend) {
					error = promise;
					break;
				}
			}

			// We haven't recovered and we know at this point that there is no
			// Suspense component higher up in the tree
			if (error instanceof Error) {
				throw error;
			}
		}

		oldCatchError(error, vnode, oldVNode);
	};

	options._root = (vnode, parentNode) => {
		if (!parentNode) {
			throw new Error('Undefined parent passed to render(), this is the second argument.\nCheck if the element is available in the DOM/has the correct id.');
		}
		let isValid;
		switch (parentNode.nodeType) {
			case ELEMENT_NODE:
			case DOCUMENT_FRAGMENT_NODE:
			case DOCUMENT_NODE: isValid = true; break;
			default: isValid = false;
		}
		if (!isValid) throw new Error(`
			Expected a valid HTML node as a second argument to render.
			Received ${parentNode} instead: render(<${vnode.type.name || vnode.type} />, ${parentNode});
		`);

		if (oldRoot) oldRoot(vnode, parentNode);
	};

	options._diff = vnode => {
		let { type, _parent: parent } = vnode;
		let parentVNode = getClosestDomNodeParent(parent);

		if (type===undefined) {
			throw new Error('Undefined component passed to createElement()\n\n'+
			'You likely forgot to export your component or might have mixed up default and named imports'+
			serializeVNode(vnode));
		}
		else if (type!=null && typeof type==='object') {
			if (type._lastDomChild!==undefined && type._dom!==undefined) {
				let info = 'Did you accidentally pass a JSX literal as JSX twice?\n\n'+
				'  let My'+getDisplayName(type)+' = '+serializeVNode(type)+';\n'+
				'  let vnode = <My'+getDisplayName(type)+' />;\n\n'+
				'This usually happens when you export a JSX literal and not the component.';
				throw new Error('Invalid type passed to createElement(): '+type+'\n\n'+info+'\n');
			}

			throw new Error('Invalid type passed to createElement(): '+(Array.isArray(type) ? 'array' : type));
		}

		if ((type==='thead' || type==='tfoot' || type==='tbody') && parentVNode.type!=='table') {
			console.error(
				'Improper nesting of table.' +
				'Your <thead/tbody/tfoot> should have a <table> parent.'
				+ serializeVNode(vnode)
			);
		}
		else if (
			type==='tr' && (
				parentVNode.type!=='thead' &&
				parentVNode.type!=='tfoot' &&
				parentVNode.type!=='tbody' &&
				parentVNode.type!=='table'
			)) {
			console.error(
				'Improper nesting of table.' +
				'Your <tr> should have a <thead/tbody/tfoot/table> parent.'
				+ serializeVNode(vnode)
			);
		}
		else if (type==='td' && parentVNode.type!=='tr') {
			console.error(
				'Improper nesting of table.' +
					'Your <td> should have a <tr> parent.'
					+ serializeVNode(vnode)
			);
		}
		else if (type==='th' && parentVNode.type!=='tr') {
			console.error(
				'Improper nesting of table.' +
				'Your <th> should have a <tr>.'
				+ serializeVNode(vnode)
			);
		}

		if (
			vnode.ref!==undefined &&
			typeof vnode.ref!=='function' &&
			typeof vnode.ref!=='object' &&
			!('$$typeof' in vnode)  // allow string refs when preact-compat is installed
		) {
			throw new Error(
				`Component's "ref" property should be a function, or an object created ` +
				`by createRef(), but got [${typeof vnode.ref}] instead\n` +
				serializeVNode(vnode)
			);
		}

		if (typeof vnode.type==='string') {
			for (const key in vnode.props) {
				if (key[0]==='o' && key[1]==='n' && typeof vnode.props[key]!=='function' && vnode.props[key]!=null) {
					throw new Error(
						`Component's "${key}" property should be a function, ` +
						`but got [${typeof vnode.props[key]}] instead\n` +
						serializeVNode(vnode)
					);
				}
			}
		}

		// Check prop-types if available
		if (typeof vnode.type==='function' && vnode.type.propTypes) {
			if (vnode.type.displayName === 'Lazy' && !warnedComponents.lazyPropTypes[vnode.type]) {
				const m = 'PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ';
				try {
					const lazyVNode = vnode.type();
					warnedComponents.lazyPropTypes[vnode.type] = true;
					console.warn(m + 'Component wrapped in lazy() is ' + (lazyVNode.type.displayName || lazyVNode.type.name));
				}
				catch (promise) {
					console.warn(m + 'We will log the wrapped component\'s name once it is loaded.');
				}
			}
			checkPropTypes(vnode.type.propTypes, vnode.props, getDisplayName(vnode), serializeVNode(vnode));
		}

		if (oldBeforeDiff) oldBeforeDiff(vnode);
	};

	options._hook = (comp) => {
		if (!comp) {
			throw new Error('Hook can only be invoked from render methods.');
		}

		if (oldHook) oldHook(comp);
	};

	const warn = (property, err) => ({
		get() {
			throw new Error(`getting vnode.${property} is deprecated, ${err}`);
		},
		set() {
			throw new Error(`setting vnode.${property} is not allowed, ${err}`);
		}
	});

	const deprecatedAttributes = {
		nodeName: warn('nodeName', 'use vnode.type'),
		attributes: warn('attributes', 'use vnode.props'),
		children: warn('children', 'use vnode.props.children')
	};

	options.vnode = (vnode) => {
		let source, self;
		if (vnode.props && vnode.props.__source) {
			source = vnode.props.__source;
			delete vnode.props.__source;
		}
		if (vnode.props && vnode.props.__self) {
			self = vnode.props.__self;
			delete vnode.props.__self;
		}
		vnode.__self = self;
		vnode.__source = source;
		Object.defineProperties(vnode, deprecatedAttributes);
		if (oldVnode) oldVnode(vnode);
	};

	options.diffed = (vnode) => {
		// Check if the user passed plain objects as children. Note that we cannot
		// move this check into `options.vnode` because components can receive
		// children in any shape they want (e.g.
		// `<MyJSONFormatter>{{ foo: 123, bar: "abc" }}</MyJSONFormatter>`).
		// Putting this check in `options.diffed` ensures that
		// `vnode._children` is set and that we only validate the children
		// that were actually rendered.
		if (vnode._children) {
			vnode._children.forEach(child => {
				if (child && child.type===undefined) {
					// Remove internal vnode keys that will always be patched
					delete child._parent;
					delete child._depth;
					const keys = Object.keys(child).join(',');
					throw new Error(`Objects are not valid as a child. Encountered an object with the keys {${keys}}.`);
				}
			});
		}

		if (oldDiffed) oldDiffed(vnode);

		if (vnode._component && vnode._component.__hooks) {
			let hooks = vnode._component.__hooks;
			if (Array.isArray(hooks._list)) {
				hooks._list.forEach(hook => {
					if (hook._callback && (!hook._args || !Array.isArray(hook._args))) {
						console.warn(
							`In ${getDisplayName(vnode)} you are calling useMemo/useCallback without passing arguments.\n` +
							`This is a noop since it will not be able to memoize, it will execute it every render.`
						);
					}
				});
			}
			if (Array.isArray(hooks._pendingEffects)) {
				hooks._pendingEffects.forEach((effect) => {
					if ((!effect._args || !Array.isArray(effect._args)) && !warnedComponents.useEffect[vnode.type]) {
						warnedComponents.useEffect[vnode.type] = true;
						console.warn('You should provide an array of arguments as the second argument to the "useEffect" hook.\n\n' +
							'Not doing so will invoke this effect on every render.\n\n' +
							'This effect can be found in the render of ' + getDisplayName(vnode) + '.');
					}
				});
			}
			if (Array.isArray(hooks._pendingLayoutEffects)) {
				hooks._pendingLayoutEffects.forEach((layoutEffect) => {
					if ((!layoutEffect._args || !Array.isArray(layoutEffect._args)) && !warnedComponents.useLayoutEffect[vnode.type]) {
						warnedComponents.useLayoutEffect[vnode.type] = true;
						console.warn('You should provide an array of arguments as the second argument to the "useLayoutEffect" hook.\n\n' +
							'Not doing so will invoke this effect on every render.\n\n' +
							'This effect can be found in the render of ' + getDisplayName(vnode) + '.');
					}
				});
			}
		}

		if (vnode._children != null) {
			const keys = [];
			for (let i = 0; i < vnode._children.length; i++) {
				const child = vnode._children[i];
				if (!child || child.key==null) continue;

				const key = child.key;
				if (keys.indexOf(key) !== -1) {
					console.error(
						'Following component has two or more children with the ' +
						`same key attribute: "${key}". This may cause glitches and misbehavior ` +
						'in rendering process. Component: \n\n' +
						serializeVNode(vnode)
					);

					// Break early to not spam the console
					break;
				}

				keys.push(key);
			}
		}
	};
}

const setState = Component.prototype.setState;
Component.prototype.setState = function(update, callback) {
	if (this._vnode==null) {
		console.warn(
			`Calling "this.setState" inside the constructor of a component is a ` +
			`no-op and might be a bug in your application. Instead, set ` +
			`"this.state = {}" directly.`
		);
	}
	else if (this._parentDom==null) {
		console.warn(
			`Can't call "this.setState" on an unmounted component. This is a no-op, ` +
			`but it indicates a memory leak in your application. To fix, cancel all ` +
			`subscriptions and asynchronous tasks in the componentWillUnmount method.`
		);
	}

	return setState.call(this, update, callback);
};

const forceUpdate = Component.prototype.forceUpdate;
Component.prototype.forceUpdate = function(callback) {
	if (this._vnode==null) {
		console.warn(
			`Calling "this.forceUpdate" inside the constructor of a component is a ` +
			`no-op and might be a bug in your application.`
		);
	}
	else if (this._parentDom==null) {
		console.warn(
			`Can't call "this.setState" on an unmounted component. This is a no-op, ` +
			`but it indicates a memory leak in your application. To fix, cancel all ` +
			`subscriptions and asynchronous tasks in the componentWillUnmount method.`
		);
	}
	return forceUpdate.call(this, callback);
};

/**
 * Serialize a vnode tree to a string
 * @param {import('./internal').VNode} vnode
 * @returns {string}
 */
export function serializeVNode(vnode) {
	let { props } = vnode;
	let name = getDisplayName(vnode);

	let attrs = '';
	for (let prop in props) {
		if (props.hasOwnProperty(prop) && prop!=='children') {
			let value = props[prop];

			// If it is an object but doesn't have toString(), use Object.toString
			if (typeof value==='function') {
				value = `function ${value.displayName || value.name}() {}`;
			}

			value = Object(value) === value && !value.toString
				? Object.prototype.toString.call(value)
				: value + '';

			attrs += ` ${prop}=${JSON.stringify(value)}`;
		}
	}

	let children = props.children;
	return `<${name}${attrs}${children && children.length
		? '>..</'+name+'>'
		: ' />'}`;
}
<commit_msg>Fix argumentless useLayoutEffect debug test<commit_after>import { checkPropTypes } from './check-props';
import { getDisplayName } from './devtools/custom';
import { options, Component } from 'preact';
import { ELEMENT_NODE, DOCUMENT_NODE, DOCUMENT_FRAGMENT_NODE } from './constants';

function getClosestDomNodeParent(parent) {
	if (!parent) return {};
	if (typeof parent.type === 'function') {
		return getClosestDomNodeParent(parent._parent);
	}
	return parent;
}

export function initDebug() {
	/* eslint-disable no-console */
	let oldBeforeDiff = options._diff;
	let oldDiffed = options.diffed;
	let oldVnode = options.vnode;
	let oldCatchError = options._catchError;
	let oldRoot = options._root;
	let oldHook = options._hook;
	const warnedComponents = { useEffect: {}, useLayoutEffect: {}, lazyPropTypes: {} };

	options._catchError = (error, vnode, oldVNode) => {
		let component = vnode && vnode._component;
		if (component && typeof error.then === 'function') {
			const promise = error;
			error = new Error('Missing Suspense. The throwing component was: ' + getDisplayName(vnode));

			let parent = vnode;
			for (; parent; parent = parent._parent) {
				if (parent._component && parent._component._childDidSuspend) {
					error = promise;
					break;
				}
			}

			// We haven't recovered and we know at this point that there is no
			// Suspense component higher up in the tree
			if (error instanceof Error) {
				throw error;
			}
		}

		oldCatchError(error, vnode, oldVNode);
	};

	options._root = (vnode, parentNode) => {
		if (!parentNode) {
			throw new Error('Undefined parent passed to render(), this is the second argument.\nCheck if the element is available in the DOM/has the correct id.');
		}
		let isValid;
		switch (parentNode.nodeType) {
			case ELEMENT_NODE:
			case DOCUMENT_FRAGMENT_NODE:
			case DOCUMENT_NODE: isValid = true; break;
			default: isValid = false;
		}
		if (!isValid) throw new Error(`
			Expected a valid HTML node as a second argument to render.
			Received ${parentNode} instead: render(<${vnode.type.name || vnode.type} />, ${parentNode});
		`);

		if (oldRoot) oldRoot(vnode, parentNode);
	};

	options._diff = vnode => {
		let { type, _parent: parent } = vnode;
		let parentVNode = getClosestDomNodeParent(parent);

		if (type===undefined) {
			throw new Error('Undefined component passed to createElement()\n\n'+
			'You likely forgot to export your component or might have mixed up default and named imports'+
			serializeVNode(vnode));
		}
		else if (type!=null && typeof type==='object') {
			if (type._lastDomChild!==undefined && type._dom!==undefined) {
				let info = 'Did you accidentally pass a JSX literal as JSX twice?\n\n'+
				'  let My'+getDisplayName(type)+' = '+serializeVNode(type)+';\n'+
				'  let vnode = <My'+getDisplayName(type)+' />;\n\n'+
				'This usually happens when you export a JSX literal and not the component.';
				throw new Error('Invalid type passed to createElement(): '+type+'\n\n'+info+'\n');
			}

			throw new Error('Invalid type passed to createElement(): '+(Array.isArray(type) ? 'array' : type));
		}

		if ((type==='thead' || type==='tfoot' || type==='tbody') && parentVNode.type!=='table') {
			console.error(
				'Improper nesting of table.' +
				'Your <thead/tbody/tfoot> should have a <table> parent.'
				+ serializeVNode(vnode)
			);
		}
		else if (
			type==='tr' && (
				parentVNode.type!=='thead' &&
				parentVNode.type!=='tfoot' &&
				parentVNode.type!=='tbody' &&
				parentVNode.type!=='table'
			)) {
			console.error(
				'Improper nesting of table.' +
				'Your <tr> should have a <thead/tbody/tfoot/table> parent.'
				+ serializeVNode(vnode)
			);
		}
		else if (type==='td' && parentVNode.type!=='tr') {
			console.error(
				'Improper nesting of table.' +
					'Your <td> should have a <tr> parent.'
					+ serializeVNode(vnode)
			);
		}
		else if (type==='th' && parentVNode.type!=='tr') {
			console.error(
				'Improper nesting of table.' +
				'Your <th> should have a <tr>.'
				+ serializeVNode(vnode)
			);
		}

		if (
			vnode.ref!==undefined &&
			typeof vnode.ref!=='function' &&
			typeof vnode.ref!=='object' &&
			!('$$typeof' in vnode)  // allow string refs when preact-compat is installed
		) {
			throw new Error(
				`Component's "ref" property should be a function, or an object created ` +
				`by createRef(), but got [${typeof vnode.ref}] instead\n` +
				serializeVNode(vnode)
			);
		}

		if (typeof vnode.type==='string') {
			for (const key in vnode.props) {
				if (key[0]==='o' && key[1]==='n' && typeof vnode.props[key]!=='function' && vnode.props[key]!=null) {
					throw new Error(
						`Component's "${key}" property should be a function, ` +
						`but got [${typeof vnode.props[key]}] instead\n` +
						serializeVNode(vnode)
					);
				}
			}
		}

		// Check prop-types if available
		if (typeof vnode.type==='function' && vnode.type.propTypes) {
			if (vnode.type.displayName === 'Lazy' && !warnedComponents.lazyPropTypes[vnode.type]) {
				const m = 'PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ';
				try {
					const lazyVNode = vnode.type();
					warnedComponents.lazyPropTypes[vnode.type] = true;
					console.warn(m + 'Component wrapped in lazy() is ' + (lazyVNode.type.displayName || lazyVNode.type.name));
				}
				catch (promise) {
					console.warn(m + 'We will log the wrapped component\'s name once it is loaded.');
				}
			}
			checkPropTypes(vnode.type.propTypes, vnode.props, getDisplayName(vnode), serializeVNode(vnode));
		}

		if (oldBeforeDiff) oldBeforeDiff(vnode);
	};

	options._hook = (comp) => {
		if (!comp) {
			throw new Error('Hook can only be invoked from render methods.');
		}

		if (oldHook) oldHook(comp);
	};

	const warn = (property, err) => ({
		get() {
			throw new Error(`getting vnode.${property} is deprecated, ${err}`);
		},
		set() {
			throw new Error(`setting vnode.${property} is not allowed, ${err}`);
		}
	});

	const deprecatedAttributes = {
		nodeName: warn('nodeName', 'use vnode.type'),
		attributes: warn('attributes', 'use vnode.props'),
		children: warn('children', 'use vnode.props.children')
	};

	options.vnode = (vnode) => {
		let source, self;
		if (vnode.props && vnode.props.__source) {
			source = vnode.props.__source;
			delete vnode.props.__source;
		}
		if (vnode.props && vnode.props.__self) {
			self = vnode.props.__self;
			delete vnode.props.__self;
		}
		vnode.__self = self;
		vnode.__source = source;
		Object.defineProperties(vnode, deprecatedAttributes);
		if (oldVnode) oldVnode(vnode);
	};

	options.diffed = (vnode) => {
		// Check if the user passed plain objects as children. Note that we cannot
		// move this check into `options.vnode` because components can receive
		// children in any shape they want (e.g.
		// `<MyJSONFormatter>{{ foo: 123, bar: "abc" }}</MyJSONFormatter>`).
		// Putting this check in `options.diffed` ensures that
		// `vnode._children` is set and that we only validate the children
		// that were actually rendered.
		if (vnode._children) {
			vnode._children.forEach(child => {
				if (child && child.type===undefined) {
					// Remove internal vnode keys that will always be patched
					delete child._parent;
					delete child._depth;
					const keys = Object.keys(child).join(',');
					throw new Error(`Objects are not valid as a child. Encountered an object with the keys {${keys}}.`);
				}
			});
		}

		if (vnode._component && vnode._component.__hooks) {
			let hooks = vnode._component.__hooks;
			if (Array.isArray(hooks._list)) {
				hooks._list.forEach(hook => {
					if (hook._callback && (!hook._args || !Array.isArray(hook._args))) {
						console.warn(
							`In ${getDisplayName(vnode)} you are calling useMemo/useCallback without passing arguments.\n` +
							`This is a noop since it will not be able to memoize, it will execute it every render.`
						);
					}
				});
			}
			if (Array.isArray(hooks._pendingEffects)) {
				hooks._pendingEffects.forEach((effect) => {
					if ((!effect._args || !Array.isArray(effect._args)) && !warnedComponents.useEffect[vnode.type]) {
						warnedComponents.useEffect[vnode.type] = true;
						console.warn('You should provide an array of arguments as the second argument to the "useEffect" hook.\n\n' +
							'Not doing so will invoke this effect on every render.\n\n' +
							'This effect can be found in the render of ' + getDisplayName(vnode) + '.');
					}
				});
			}
			if (Array.isArray(hooks._pendingLayoutEffects)) {
				hooks._pendingLayoutEffects.forEach((layoutEffect) => {
					if ((!layoutEffect._args || !Array.isArray(layoutEffect._args)) && !warnedComponents.useLayoutEffect[vnode.type]) {
						warnedComponents.useLayoutEffect[vnode.type] = true;
						console.warn('You should provide an array of arguments as the second argument to the "useLayoutEffect" hook.\n\n' +
							'Not doing so will invoke this effect on every render.\n\n' +
							'This effect can be found in the render of ' + getDisplayName(vnode) + '.');
					}
				});
			}
		}

		if (oldDiffed) oldDiffed(vnode);

		if (vnode._children != null) {
			const keys = [];
			for (let i = 0; i < vnode._children.length; i++) {
				const child = vnode._children[i];
				if (!child || child.key==null) continue;

				const key = child.key;
				if (keys.indexOf(key) !== -1) {
					console.error(
						'Following component has two or more children with the ' +
						`same key attribute: "${key}". This may cause glitches and misbehavior ` +
						'in rendering process. Component: \n\n' +
						serializeVNode(vnode)
					);

					// Break early to not spam the console
					break;
				}

				keys.push(key);
			}
		}
	};
}

const setState = Component.prototype.setState;
Component.prototype.setState = function(update, callback) {
	if (this._vnode==null) {
		console.warn(
			`Calling "this.setState" inside the constructor of a component is a ` +
			`no-op and might be a bug in your application. Instead, set ` +
			`"this.state = {}" directly.`
		);
	}
	else if (this._parentDom==null) {
		console.warn(
			`Can't call "this.setState" on an unmounted component. This is a no-op, ` +
			`but it indicates a memory leak in your application. To fix, cancel all ` +
			`subscriptions and asynchronous tasks in the componentWillUnmount method.`
		);
	}

	return setState.call(this, update, callback);
};

const forceUpdate = Component.prototype.forceUpdate;
Component.prototype.forceUpdate = function(callback) {
	if (this._vnode==null) {
		console.warn(
			`Calling "this.forceUpdate" inside the constructor of a component is a ` +
			`no-op and might be a bug in your application.`
		);
	}
	else if (this._parentDom==null) {
		console.warn(
			`Can't call "this.setState" on an unmounted component. This is a no-op, ` +
			`but it indicates a memory leak in your application. To fix, cancel all ` +
			`subscriptions and asynchronous tasks in the componentWillUnmount method.`
		);
	}
	return forceUpdate.call(this, callback);
};

/**
 * Serialize a vnode tree to a string
 * @param {import('./internal').VNode} vnode
 * @returns {string}
 */
export function serializeVNode(vnode) {
	let { props } = vnode;
	let name = getDisplayName(vnode);

	let attrs = '';
	for (let prop in props) {
		if (props.hasOwnProperty(prop) && prop!=='children') {
			let value = props[prop];

			// If it is an object but doesn't have toString(), use Object.toString
			if (typeof value==='function') {
				value = `function ${value.displayName || value.name}() {}`;
			}

			value = Object(value) === value && !value.toString
				? Object.prototype.toString.call(value)
				: value + '';

			attrs += ` ${prop}=${JSON.stringify(value)}`;
		}
	}

	let children = props.children;
	return `<${name}${attrs}${children && children.length
		? '>..</'+name+'>'
		: ' />'}`;
}
<|endoftext|>


<commit_before>/* =============================================================
 * bootstrap-collapse.js v2.0.3
 * http://twitter.github.com/bootstrap/javascript.html#collapse
 * =============================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================ */

!function ($) {

  "use strict"; // jshint ;_;

 /* COLLAPSE PUBLIC CLASS DEFINITION
  * ================================ */

  var Collapse = function (element, options) {
    this.$element = $(element)
    this.options = $.extend({}, $.fn.collapse.defaults, options)

    if (this.options.parent) {
      this.$parent = $(this.options.parent)
    }

    this.options.toggle && this.toggle()
  }

  Collapse.prototype = {

    constructor: Collapse

  , dimension: function () {
      var hasWidth = this.$element.hasClass('width')
      return hasWidth ? 'width' : 'height'
    }

  , show: function () {
      var dimension
        , scroll
        , actives
        , hasData

      if (this.transitioning) return

      dimension = this.dimension()
      scroll = $.camelCase(['scroll', dimension].join('-'))
      actives = this.$parent && this.$parent.find('> .accordion-group > .in')

      if (actives && actives.length) {
        hasData = actives.data('collapse')
        if (hasData && hasData.transitioning) return
        actives.collapse('hide')
        hasData || actives.data('collapse', null)
      }

      this.$element[dimension](0)
      this.transition('addClass', $.Event('show'), 'shown')
      this.$element[dimension](this.$element[0][scroll])
    }

  , hide: function () {
      var dimension
      if (this.transitioning) return
      dimension = this.dimension()
      this.reset(this.$element[dimension]())
      this.transition('removeClass', $.Event('hide'), 'hidden')
      this.$element[dimension](0)
    }

  , reset: function (size) {
      var dimension = this.dimension()

      this.$element
        .removeClass('collapse')
        [dimension](size || 'auto')
        [0].offsetWidth

      this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')

      return this
    }

  , transition: function (method, startEvent, completeEvent) {
      var that = this
        , complete = function () {
            if (startEvent == 'show') that.reset()
            that.transitioning = 0
            that.$element.trigger(completeEvent)
          }

      this.$element.trigger(startEvent)

      if (startEvent.isDefaultPrevented()) return

      this.transitioning = 1

      this.$element[method]('in')

      $.support.transition && this.$element.hasClass('collapse') ?
        this.$element.one($.support.transition.end, complete) :
        complete()
    }

  , toggle: function () {
      this[this.$element.hasClass('in') ? 'hide' : 'show']()
    }

  }

 /* COLLAPSIBLE PLUGIN DEFINITION
  * ============================== */

  $.fn.collapse = function (option) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('collapse')
        , options = typeof option == 'object' && option
      if (!data) $this.data('collapse', (data = new Collapse(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.collapse.defaults = {
    toggle: true
  }

  $.fn.collapse.Constructor = Collapse

 /* COLLAPSIBLE DATA-API
  * ==================== */

  $(function () {
    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
      var $this = $(this), href
        , target = $this.attr('data-target')
          || e.preventDefault()
          || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
        , option = $(target).data('collapse') ? 'toggle' : $this.data()
      $(target).collapse(option)
    })
  })

}(window.jQuery);<commit_msg>fix collapse regression<commit_after>/* =============================================================
 * bootstrap-collapse.js v2.0.3
 * http://twitter.github.com/bootstrap/javascript.html#collapse
 * =============================================================
 * Copyright 2012 Twitter, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ============================================================ */

!function ($) {

  "use strict"; // jshint ;_;

 /* COLLAPSE PUBLIC CLASS DEFINITION
  * ================================ */

  var Collapse = function (element, options) {
    this.$element = $(element)
    this.options = $.extend({}, $.fn.collapse.defaults, options)

    if (this.options.parent) {
      this.$parent = $(this.options.parent)
    }

    this.options.toggle && this.toggle()
  }

  Collapse.prototype = {

    constructor: Collapse

  , dimension: function () {
      var hasWidth = this.$element.hasClass('width')
      return hasWidth ? 'width' : 'height'
    }

  , show: function () {
      var dimension
        , scroll
        , actives
        , hasData

      if (this.transitioning) return

      dimension = this.dimension()
      scroll = $.camelCase(['scroll', dimension].join('-'))
      actives = this.$parent && this.$parent.find('> .accordion-group > .in')

      if (actives && actives.length) {
        hasData = actives.data('collapse')
        if (hasData && hasData.transitioning) return
        actives.collapse('hide')
        hasData || actives.data('collapse', null)
      }

      this.$element[dimension](0)
      this.transition('addClass', $.Event('show'), 'shown')
      this.$element[dimension](this.$element[0][scroll])
    }

  , hide: function () {
      var dimension
      if (this.transitioning) return
      dimension = this.dimension()
      this.reset(this.$element[dimension]())
      this.transition('removeClass', $.Event('hide'), 'hidden')
      this.$element[dimension](0)
    }

  , reset: function (size) {
      var dimension = this.dimension()

      this.$element
        .removeClass('collapse')
        [dimension](size || 'auto')
        [0].offsetWidth

      this.$element[size !== null ? 'addClass' : 'removeClass']('collapse')

      return this
    }

  , transition: function (method, startEvent, completeEvent) {
      var that = this
        , complete = function () {
            if (startEvent.type == 'show') that.reset()
            that.transitioning = 0
            that.$element.trigger(completeEvent)
          }

      this.$element.trigger(startEvent)

      if (startEvent.isDefaultPrevented()) return

      this.transitioning = 1

      this.$element[method]('in')

      $.support.transition && this.$element.hasClass('collapse') ?
        this.$element.one($.support.transition.end, complete) :
        complete()
    }

  , toggle: function () {
      this[this.$element.hasClass('in') ? 'hide' : 'show']()
    }

  }

 /* COLLAPSIBLE PLUGIN DEFINITION
  * ============================== */

  $.fn.collapse = function (option) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('collapse')
        , options = typeof option == 'object' && option
      if (!data) $this.data('collapse', (data = new Collapse(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.collapse.defaults = {
    toggle: true
  }

  $.fn.collapse.Constructor = Collapse

 /* COLLAPSIBLE DATA-API
  * ==================== */

  $(function () {
    $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
      var $this = $(this), href
        , target = $this.attr('data-target')
          || e.preventDefault()
          || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
        , option = $(target).data('collapse') ? 'toggle' : $this.data()
      $(target).collapse(option)
    })
  })

}(window.jQuery);<|endoftext|>


<commit_before>/*
 * Implements a user-facing modal confirmation when link has a
 * "data-confirm" attribute using bootstrap's modals. MIT license.
 *
 *   - vjt@openssl.it  Tue Jul  2 18:45:15 CEST 2013
 */
(function ($) {

  /**
   * Builds the markup for a [Bootstrap modal](http://twitter.github.io/bootstrap/javascript.html#modals)
   * for the given `element`. Uses the following `data-` parameters to
   * customize it:
   *
   *  * `data-confirm`: Contains the modal body text. HTML is allowed.
   *                    Separate multiple paragraphs using \n\n.
   *  * `data-commit`:  The 'confirm' button text. "Confirm" by default.
   *  * `data-cancel`:  The 'cancel' button text. "Cancel" by default.
   *  * `data-verify`:  Adds a text input in which the user has to input
   *                    the text in this attribute value for the 'confirm'
   *                    button to be clickable. Optional.
   *  * `data-verify-text`:  Adds a label for the data-verify input. Optional
   *  * `data-focus`:   Define focused input. Supported values are
   *                    'cancel' or 'commit', 'cancel' is default for
   *                    data-method DELETE, 'commit' for all others.
   *
   * You can set global setting using `dataConfirmModal.setDefaults`, for example:
   *
   *    dataConfirmModal.setDefaults({
   *      title: 'Confirm your action',
   *      commit: 'Continue',
   *      cancel: 'Cancel',
   *      fade:   false,
   *      verifyClass: 'form-control',
   *    });
   *
   */

  var defaults = {
    title: 'Are you sure?',
    commit: 'Confirm',
    commitClass: 'btn-danger',
    cancel: 'Cancel',
    cancelClass: 'btn-default',
    fade: true,
    verifyClass: '',
    elements: ['a[data-confirm]', 'button[data-confirm]', 'input[type=submit][data-confirm]'],
    focus: 'commit'
  };

  var settings;

  window.dataConfirmModal = {
    setDefaults: function (newSettings) {
      settings = $.extend(settings, newSettings);
    },

    restoreDefaults: function () {
      settings = $.extend({}, defaults);
    },

    confirm: function (options) {
      // Build an ephemeral modal
      //
      var modal = buildModal (options);

      modal.modal('show');
      modal.on('hidden.bs.modal', function () {
        modal.remove();
      });

      modal.find('.commit').on('click', function () {
        if (options.onConfirm && options.onConfirm.call)
          options.onConfirm.call();

        modal.modal('hide');
      });

      modal.find('.cancel').on('click', function () {
        if (options.onCancel && options.onCancel.call)
          options.onCancel.call();

        modal.modal('hide');
      });
    }
  };

  dataConfirmModal.restoreDefaults();

  var buildElementModal = function (element) {
    var options = {
      title:        element.attr('title') || element.data('original-title'),
      text:         element.data('confirm'),
      commit:       element.data('commit'),
      commitClass:  element.data('commit-class'),
      cancel:       element.data('cancel'),
      cancelClass:  element.data('cancel-class'),
      remote:       element.data('remote'),
      verify:       element.data('verify'),
      verifyRegexp: element.data('verify-regexp'),
      verifyLabel:  element.data('verify-text'),
      verifyRegexpCaseInsensitive: element.data('verify-regexp-caseinsensitive')
    };

    var modal = buildModal (options);

    modal.data('confirmed', false);
    modal.find('.commit').on('click', function () {
      modal.data('confirmed', true);
      element.trigger('click');
      modal.modal('hide');
    });

    return modal;
  }

  var buildModal = function (options) {
    var id = 'confirm-modal-' + String(Math.random()).slice(2, -1);
    var fade = settings.fade ? 'fade' : '';

    var modal = $(
      '
' +
        '
' +
          '
' +
            '
' +
              '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
              '

 ' +
            '
' +
            '

' +
            '
' +
              '<button class="btn cancel" data-dismiss="modal" aria-hidden="true"></button>' +
              '<button class="btn commit"></button>' +
            '
'+
          '
'+
        '
'+
      '
'
    );

    modal.find('.modal-title').text(options.title || settings.title);

    var body = modal.find('.modal-body');

    $.each((options.text||'').split(/\n{2}/), function (i, piece) {
      body.append($('
').html(piece));
    });

    var commit = modal.find('.commit');
    commit.text(options.commit || settings.commit);
    commit.addClass(options.commitClass || settings.commitClass);

    var cancel = modal.find('.cancel');
    cancel.text(options.cancel || settings.cancel);
    cancel.addClass(options.cancelClass || settings.cancelClass);

    if (options.remote) {
      commit.attr('data-dismiss', 'modal');
    }

    if (options.verify || options.verifyRegexp) {
      commit.prop('disabled', true);

      var isMatch;
      if (options.verifyRegexp) {
        var caseInsensitive = options.verifyRegexpCaseInsensitive;
        var re = new RegExp(regexp, caseInsensitive ? 'i' : '');

        isMatch = function (input) { return input.match(re) };
      } else {
        isMatch = function (input) { return options.verify == input };
      }

      var verification = $('<input/>', {"type": 'text', "class": settings.verifyClass}).on('keyup', function () {
        commit.prop('disabled', !isMatch($(this).val()));
      });

      modal.on('shown', function () {
        verification.focus();
      });

      modal.on('hide', function () {
        verification.val('').trigger('keyup');
      });

      if (options.verifyLabel)
        body.append($('
', {text: options.verifyLabel}))

      body.append(verification);
    }

    $('body').append(modal);

    return modal;
  };

  /**
   * Returns a modal already built for the given element or builds a new one,
   * caching it into the element's `confirm-modal` data attribute.
   */
  var getModal = function (element) {
    var modal = element.data('confirm-modal') || buildElementModal(element);

    if (modal && !element.data('confirm-modal'))
      element.data('confirm-modal', modal);

    return modal;
  };

  $.fn.confirmModal = function () {
    getModal($(this)).modal('show');

    return this;
  };

  if ($.rails) {
    /**
     * Attaches to the Rails' UJS adapter 'confirm' event on links having a
     * `data-confirm` attribute. Temporarily overrides the `$.rails.confirm`
     * function with an anonymous one that returns the 'confirmed' status of
     * the modal.
     *
     * A modal is considered 'confirmed' when an user has successfully clicked
     * the 'confirm' button in it.
     */
    $(document).delegate(settings.elements.join(', '), 'confirm', function() {
      var element = $(this), modal = getModal(element);
      var confirmed = modal.data('confirmed');

      if (!confirmed && !modal.is(':visible')) {
        modal.modal('show');

        var confirm = $.rails.confirm;
        $.rails.confirm = function () { return modal.data('confirmed'); }
        var focus_element;
        if (element.data('focus')) {
          focus_element = element.data('focus');
        } else if (element.data('method')=='delete') {
          focus_element = 'cancel'
        } else {
          focus_element = settings.focus;
        }
        modal.on('shown.bs.modal', function () { modal.find('.' + focus_element).focus(); });
        modal.on('hide', function () { $.rails.confirm = confirm; });
      }

      return confirmed;
    });
  }

})(jQuery);
<commit_msg>Move focus code in modal initialization<commit_after>/*
 * Implements a user-facing modal confirmation when link has a
 * "data-confirm" attribute using bootstrap's modals. MIT license.
 *
 *   - vjt@openssl.it  Tue Jul  2 18:45:15 CEST 2013
 */
(function ($) {

  /**
   * Builds the markup for a [Bootstrap modal](http://twitter.github.io/bootstrap/javascript.html#modals)
   * for the given `element`. Uses the following `data-` parameters to
   * customize it:
   *
   *  * `data-confirm`: Contains the modal body text. HTML is allowed.
   *                    Separate multiple paragraphs using \n\n.
   *  * `data-commit`:  The 'confirm' button text. "Confirm" by default.
   *  * `data-cancel`:  The 'cancel' button text. "Cancel" by default.
   *  * `data-verify`:  Adds a text input in which the user has to input
   *                    the text in this attribute value for the 'confirm'
   *                    button to be clickable. Optional.
   *  * `data-verify-text`:  Adds a label for the data-verify input. Optional
   *  * `data-focus`:   Define focused input. Supported values are
   *                    'cancel' or 'commit', 'cancel' is default for
   *                    data-method DELETE, 'commit' for all others.
   *
   * You can set global setting using `dataConfirmModal.setDefaults`, for example:
   *
   *    dataConfirmModal.setDefaults({
   *      title: 'Confirm your action',
   *      commit: 'Continue',
   *      cancel: 'Cancel',
   *      fade:   false,
   *      verifyClass: 'form-control',
   *    });
   *
   */

  var defaults = {
    title: 'Are you sure?',
    commit: 'Confirm',
    commitClass: 'btn-danger',
    cancel: 'Cancel',
    cancelClass: 'btn-default',
    fade: true,
    verifyClass: '',
    elements: ['a[data-confirm]', 'button[data-confirm]', 'input[type=submit][data-confirm]'],
    focus: 'commit'
  };

  var settings;

  window.dataConfirmModal = {
    setDefaults: function (newSettings) {
      settings = $.extend(settings, newSettings);
    },

    restoreDefaults: function () {
      settings = $.extend({}, defaults);
    },

    confirm: function (options) {
      // Build an ephemeral modal
      //
      var modal = buildModal (options);

      modal.modal('show');
      modal.on('hidden.bs.modal', function () {
        modal.remove();
      });

      modal.find('.commit').on('click', function () {
        if (options.onConfirm && options.onConfirm.call)
          options.onConfirm.call();

        modal.modal('hide');
      });

      modal.find('.cancel').on('click', function () {
        if (options.onCancel && options.onCancel.call)
          options.onCancel.call();

        modal.modal('hide');
      });
    }
  };

  dataConfirmModal.restoreDefaults();

  var buildElementModal = function (element) {
    var options = {
      title:        element.attr('title') || element.data('original-title'),
      text:         element.data('confirm'),
      focus:        element.data('focus'),
      method:       element.data('method'),
      commit:       element.data('commit'),
      commitClass:  element.data('commit-class'),
      cancel:       element.data('cancel'),
      cancelClass:  element.data('cancel-class'),
      remote:       element.data('remote'),
      verify:       element.data('verify'),
      verifyRegexp: element.data('verify-regexp'),
      verifyLabel:  element.data('verify-text'),
      verifyRegexpCaseInsensitive: element.data('verify-regexp-caseinsensitive')
    };

    var modal = buildModal (options);

    modal.data('confirmed', false);
    modal.find('.commit').on('click', function () {
      modal.data('confirmed', true);
      element.trigger('click');
      modal.modal('hide');
    });

    return modal;
  }

  var buildModal = function (options) {
    var id = 'confirm-modal-' + String(Math.random()).slice(2, -1);
    var fade = settings.fade ? 'fade' : '';

    var modal = $(
      '
' +
        '
' +
          '
' +
            '
' +
              '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
              '

 ' +
            '
' +
            '

' +
            '
' +
              '<button class="btn cancel" data-dismiss="modal" aria-hidden="true"></button>' +
              '<button class="btn commit"></button>' +
            '
'+
          '
'+
        '
'+
      '
'
    );

    modal.find('.modal-title').text(options.title || settings.title);

    var body = modal.find('.modal-body');

    $.each((options.text||'').split(/\n{2}/), function (i, piece) {
      body.append($('
').html(piece));
    });

    var commit = modal.find('.commit');
    commit.text(options.commit || settings.commit);
    commit.addClass(options.commitClass || settings.commitClass);

    var cancel = modal.find('.cancel');
    cancel.text(options.cancel || settings.cancel);
    cancel.addClass(options.cancelClass || settings.cancelClass);

    if (options.remote) {
      commit.attr('data-dismiss', 'modal');
    }

    if (options.verify || options.verifyRegexp) {
      commit.prop('disabled', true);

      var isMatch;
      if (options.verifyRegexp) {
        var caseInsensitive = options.verifyRegexpCaseInsensitive;
        var re = new RegExp(regexp, caseInsensitive ? 'i' : '');

        isMatch = function (input) { return input.match(re) };
      } else {
        isMatch = function (input) { return options.verify == input };
      }

      var verification = $('<input/>', {"type": 'text', "class": settings.verifyClass}).on('keyup', function () {
        commit.prop('disabled', !isMatch($(this).val()));
      });

      modal.on('shown', function () {
        verification.focus();
      });

      modal.on('hide', function () {
        verification.val('').trigger('keyup');
      });

      if (options.verifyLabel)
        body.append($('
', {text: options.verifyLabel}))

      body.append(verification);
    }

    var focus_element;
    if (options.focus) {
      focus_element = options.focus;
    } else if (options.method == 'delete') {
      focus_element = 'cancel'
    } else {
      focus_element = settings.focus;
    }
    focus_element = modal.find('.' + focus_element);

    modal.on('shown.bs.modal', function () {
      focus_element.focus();
    });

    $('body').append(modal);

    return modal;
  };

  /**
   * Returns a modal already built for the given element or builds a new one,
   * caching it into the element's `confirm-modal` data attribute.
   */
  var getModal = function (element) {
    var modal = element.data('confirm-modal') || buildElementModal(element);

    if (modal && !element.data('confirm-modal'))
      element.data('confirm-modal', modal);

    return modal;
  };

  $.fn.confirmModal = function () {
    getModal($(this)).modal('show');

    return this;
  };

  if ($.rails) {
    /**
     * Attaches to the Rails' UJS adapter 'confirm' event on links having a
     * `data-confirm` attribute. Temporarily overrides the `$.rails.confirm`
     * function with an anonymous one that returns the 'confirmed' status of
     * the modal.
     *
     * A modal is considered 'confirmed' when an user has successfully clicked
     * the 'confirm' button in it.
     */
    $(document).delegate(settings.elements.join(', '), 'confirm', function() {
      var element = $(this), modal = getModal(element);
      var confirmed = modal.data('confirmed');

      if (!confirmed && !modal.is(':visible')) {
        modal.modal('show');

        var confirm = $.rails.confirm;
        $.rails.confirm = function () { return modal.data('confirmed'); }
        modal.on('hide', function () { $.rails.confirm = confirm; });
      }

      return confirmed;
    });
  }

})(jQuery);
<|endoftext|>


<commit_before>import Ember from 'ember';

const { $, run } = Ember;

const tooltipOrPopoverSelector = '.ember-tooltip, .ember-popover';
const tooltipOrPopoverTargetSelector = '.ember-tooltip-or-popover-target';

const getTooltipFromBody = function(selector=tooltipOrPopoverSelector) {
  // we have to .find() tooltips from $body because sometimes
  // tooltips and popovers are rendered as children of <body>
  // instead of children of the $targetElement

  const $body = $(document.body);
  const $tooltip = $body.find(selector) ;

  if (!$tooltip.hasClass('ember-tooltip') && !$tooltip.hasClass('ember-popover')) {
    throw Error(`getTooltipFromBody(): returned an element that is not a tooltip`);
  } else if ($tooltip.length > 1) {
    throw Error('getTooltipFromBody(): Multiple tooltips were found. Please provide an {option.selector = ".specific-tooltip-class"}');
  }

  return $tooltip;
}

const getTooltipTargetFromBody = function(selector = tooltipOrPopoverTargetSelector) {
  const $body = $(document.body);
  const $tooltipTarget = $body.find(selector) ;

  if ($tooltipTarget.length > 1) {
    throw Error('getTooltipTargetFromBody(): Multiple tooltip targets were found. Please provide an {option.targetSelector = ".specific-tooltip-target-class"}');
  }

  return $tooltipTarget;
}

export function triggerTooltipTargetEvent($element, type, options={}) {

  // TODO why do we allow focusin? why not just focus?
  const approvedEventTypes = ['mouseenter', 'mouseleave', 'click', 'focus', 'focusin', 'blur'];
  if (approvedEventTypes.indexOf(type) == -1) {
    throw Error(`only ${approvedEventTypes.join(', ')} will trigger a tooltip event. You used ${type}.`);
  }

  let wasEventTriggered = false;

  if (options.selector) {
    $element = $element.find(options.selector);
  }

  // we need to need to wrap any code with asynchronous side-effects in a run
  // $tooltipTarget.trigger('someEvent') has asynchronous side-effects
  run(() => {
    // if the $tooltip is hidden then the user can't interact with it
    if ($element.attr('aria-hidden') === 'true') {
      return;
    }
    if (type === 'focus' || type === 'blur') {
      // we don't know why but this is necessary when type is 'focus' or 'blur'
      $element[0].dispatchEvent(new window.Event(type));
    } else {
      $element.trigger(type);
    }

    wasEventTriggered = true;
  });

  return wasEventTriggered;
}

export function assertTooltipNotRendered(assert, options={}) {
  const $body = $(document.body);
  const $tooltip = $body.find(options.selector || tooltipOrPopoverSelector);

  assert.equal($tooltip.length, 0, 'assertTooltipNotRendered(): the ember-tooltip should not be rendered');
}

export function assertTooltipRendered(assert, options={}) {
  const $tooltip = getTooltipFromBody(options.selector);

  assert.equal($tooltip.length, 1, 'assertTooltipRendered(): the ember-tooltip should be rendered');
}

export function assertTooltipNotVisible(assert, options={}) {
  const $tooltip = getTooltipFromBody(options.selector);
  const isTooltipNotVisible = $tooltip.attr('aria-hidden') == 'true';
  const isTooltipTetherDisabled = $tooltip.attr('data-tether-enabled') == 'false';

  assert.ok(isTooltipNotVisible && isTooltipTetherDisabled,
      `assertTooltipNotVisible(): the ember-tooltip shouldn't be visible and the tether should be disabled:
        isTooltipNotVisible -> ${isTooltipNotVisible} ;
        isTooltipTetherDisabled -> ${isTooltipTetherDisabled}`);
}

export function assertTooltipVisible(assert, options={}) {
  const $tooltip = getTooltipFromBody(options.selector);
  const isTooltipVisible = $tooltip.attr('aria-hidden') == 'false';
  const isTooltipTetherEnabled = $tooltip.attr('data-tether-enabled') == 'true';

  assert.ok(isTooltipVisible && isTooltipTetherEnabled,
      `assertTooltipVisible(): the ember-tooltip should be visible and the tether should be enabled:
        isTooltipVisible -> ${isTooltipVisible} ;
        isTooltipTetherEnabled -> ${isTooltipTetherEnabled}`);
}

export function assertTooltipSide(assert, options = {}) {
  const { side } = options;

  const sideIsValid = (
    side === 'top' ||
    side === 'right' ||
    side === 'bottom' ||
    side === 'left'
  );

  /* We make sure the side being tested is valid. We
  use Ember.assert because assert is passed in from QUnit */

  if (!sideIsValid) {
    Ember.assert(`You must pass side like assertTooltipSide(assert, { side: 'top' }); Valid options for side are top, right, bottom, and left.`);
  }

  const expectedSide = options.side || 'top';
  const $target = getTooltipTargetFromBody(options.targetSelector);
  const targetPosition = $target[0].getBoundingClientRect();
  const $tooltip = getTooltipFromBody(options.selector);
  const tooltipPosition = $tooltip[0].getBoundingClientRect();

  if (expectedSide === 'top') {
    assert.ok(targetPosition.top > tooltipPosition.bottom,
      'Tooltip should be above the target');
  } else if (expectedSide === 'right') {
    assert.ok(targetPosition.right < tooltipPosition.left,
      'Tooltip should be right of the target');
  } else if (expectedSide === 'bottom') {
    assert.ok(targetPosition.bottom < tooltipPosition.top,
      'Tooltip should be below the target');
  } else if (expectedSide === 'left') {
    assert.ok(targetPosition.left > tooltipPosition.right,
      'Tooltip should be left of the target');
  }
}
<commit_msg>Refactored side test to prep for spacing test<commit_after>import Ember from 'ember';

const { $, run } = Ember;

const tooltipOrPopoverSelector = '.ember-tooltip, .ember-popover';
const tooltipOrPopoverTargetSelector = '.ember-tooltip-or-popover-target';

function getTooltipFromBody(selector=tooltipOrPopoverSelector) {
  // we have to .find() tooltips from $body because sometimes
  // tooltips and popovers are rendered as children of <body>
  // instead of children of the $targetElement

  const $body = $(document.body);
  const $tooltip = $body.find(selector) ;

  if (!$tooltip.hasClass('ember-tooltip') && !$tooltip.hasClass('ember-popover')) {
    throw Error(`getTooltipFromBody(): returned an element that is not a tooltip`);
  } else if ($tooltip.length > 1) {
    throw Error('getTooltipFromBody(): Multiple tooltips were found. Please provide an {option.selector = ".specific-tooltip-class"}');
  }

  return $tooltip;
}

function getTooltipTargetFromBody(selector = tooltipOrPopoverTargetSelector) {
  const $body = $(document.body);
  const $tooltipTarget = $body.find(selector) ;

  if ($tooltipTarget.length > 1) {
    throw Error('getTooltipTargetFromBody(): Multiple tooltip targets were found. Please provide an {option.targetSelector = ".specific-tooltip-target-class"}');
  }

  return $tooltipTarget;
}

function validateSide(side) {
  const sideIsValid = (
    side === 'top' ||
    side === 'right' ||
    side === 'bottom' ||
    side === 'left'
  );

  /* We make sure the side being tested is valid. We
  use Ember.assert because assert is passed in from QUnit */

  if (!sideIsValid) {
    Ember.assert(`You must pass side like assertTooltipSide(assert, { side: 'top' }); Valid options for side are top, right, bottom, and left.`);
  }
}

export function triggerTooltipTargetEvent($element, type, options={}) {

  // TODO why do we allow focusin? why not just focus?
  const approvedEventTypes = ['mouseenter', 'mouseleave', 'click', 'focus', 'focusin', 'blur'];
  if (approvedEventTypes.indexOf(type) == -1) {
    throw Error(`only ${approvedEventTypes.join(', ')} will trigger a tooltip event. You used ${type}.`);
  }

  let wasEventTriggered = false;

  if (options.selector) {
    $element = $element.find(options.selector);
  }

  // we need to need to wrap any code with asynchronous side-effects in a run
  // $tooltipTarget.trigger('someEvent') has asynchronous side-effects
  run(() => {
    // if the $tooltip is hidden then the user can't interact with it
    if ($element.attr('aria-hidden') === 'true') {
      return;
    }
    if (type === 'focus' || type === 'blur') {
      // we don't know why but this is necessary when type is 'focus' or 'blur'
      $element[0].dispatchEvent(new window.Event(type));
    } else {
      $element.trigger(type);
    }

    wasEventTriggered = true;
  });

  return wasEventTriggered;
}

export function assertTooltipNotRendered(assert, options={}) {
  const $body = $(document.body);
  const $tooltip = $body.find(options.selector || tooltipOrPopoverSelector);

  assert.equal($tooltip.length, 0, 'assertTooltipNotRendered(): the ember-tooltip should not be rendered');
}

export function assertTooltipRendered(assert, options={}) {
  const $tooltip = getTooltipFromBody(options.selector);

  assert.equal($tooltip.length, 1, 'assertTooltipRendered(): the ember-tooltip should be rendered');
}

export function assertTooltipNotVisible(assert, options={}) {
  const $tooltip = getTooltipFromBody(options.selector);
  const isTooltipNotVisible = $tooltip.attr('aria-hidden') == 'true';
  const isTooltipTetherDisabled = $tooltip.attr('data-tether-enabled') == 'false';

  assert.ok(isTooltipNotVisible && isTooltipTetherDisabled,
      `assertTooltipNotVisible(): the ember-tooltip shouldn't be visible and the tether should be disabled:
        isTooltipNotVisible -> ${isTooltipNotVisible} ;
        isTooltipTetherDisabled -> ${isTooltipTetherDisabled}`);
}

export function assertTooltipVisible(assert, options={}) {
  const $tooltip = getTooltipFromBody(options.selector);
  const isTooltipVisible = $tooltip.attr('aria-hidden') == 'false';
  const isTooltipTetherEnabled = $tooltip.attr('data-tether-enabled') == 'true';

  assert.ok(isTooltipVisible && isTooltipTetherEnabled,
      `assertTooltipVisible(): the ember-tooltip should be visible and the tether should be enabled:
        isTooltipVisible -> ${isTooltipVisible} ;
        isTooltipTetherEnabled -> ${isTooltipTetherEnabled}`);
}

export function getTooltipPosition(options = {}) {
  const $target = getTooltipTargetFromBody(options.targetSelector);
  const targetPosition = $target[0].getBoundingClientRect();
  const $tooltip = getTooltipFromBody(options.selector);
  const tooltipPosition = $tooltip[0].getBoundingClientRect();

  return {
    targetPosition,
    tooltipPosition,
  };
}

export function assertTooltipSide(assert, options = {}) {
  const { side } = options;

  validateSide(side);

  const { targetPosition, tooltipPosition } = getTooltipPosition();

  let passIfTrue;

  /* When the side is top or left, the greater number
  is the target's position. Thus, we check that the
  target's position is greater than the tooltip's
  position. */

  if (side === 'top') {
    passIfTrue = targetPosition.top > tooltipPosition.bottom;
  } else if (side === 'right') {
    passIfTrue = targetPosition.right < tooltipPosition.left;
  } else if (side === 'bottom') {
    passIfTrue = targetPosition.bottom < tooltipPosition.top;
  } else if (side === 'left') {
    passIfTrue = targetPosition.left > tooltipPosition.right;
  }

  assert.ok(passIfTrue, `Tooltip should be on the ${side} side of the target`);
}
<|endoftext|>


<commit_before>/*
 Copyright 2016 - 2018 by Jan Dockx

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/* eslint-env mocha */

'use strict'

const testUtil = require('../_util/testUtil')
const common = require('./ConditionErrorCommon')
const ConditionMetaError = require('../../lib/IV/ConditionMetaError')
const ConditionViolation = require('../../lib/IV/ConditionViolation')
const conditionMetaErrorCommon = require('./ConditionMetaErrorCommon')
const must = require('must')

function isArguments (o) {
  const str = '' + o
  str.must.equal('[object Arguments]')
}

const selfVerifyCases = [
  function () { return undefined },
  function () { return null },
  function () { return {} }
]

function args () { return arguments }

const argsVerifyCases = [
  function () { return args() },
  function () { return args('an argument') },
  function () { return args('an argument', 'another argument') },
  function () { return ['an argument in an array'] }
]

function expectInvariants (subject) {
  subject.must.be.an.instanceof(ConditionViolation)
  common.expectInvariants(subject)
  testUtil.expectFrozenPropertyOnAPrototype(subject, 'verify')
  subject.verify.must.be.a.function()
  testUtil.expectFrozenPropertyOnAPrototype(subject, 'verifyAll')
  // noinspection JSUnresolvedVariable
  subject.verifyAll.must.be.a.function()
}

// noinspection ParameterNamingConventionJS
function expectProperties (exception, Type, contractFunction, condition, self, args) {
  common.expectProperties.apply(undefined, arguments)
  exception.must.be.frozen()
}

function expectConstructorPost (result, contractFunction, condition, self, args) {
  // noinspection JSUnresolvedVariable
  common.expectConstructorPost(result, contractFunction, condition, self, args, result._rawStack)
  common.expectProperties.call(undefined, result, ConditionViolation, contractFunction, condition, self, args)
  // not frozen yet
}

// noinspection JSUnusedLocalSymbols
function doctorArgs (args, boundContractFunction) {
  return args
}

// noinspection FunctionNamingConventionJS
function generatePrototypeMethodsDescriptions (oneSubjectGenerator, allSubjectGenerators) {
  common.generatePrototypeMethodsDescriptions(oneSubjectGenerator, allSubjectGenerators)

  const that = this

  describe('#verify()', function () {
    const conditionCases = [
      () => function f () {
        f.self = this
        f.args = arguments
        // no return
      },
      () => function f () {
        f.self = this
        f.args = arguments
        return false
      },
      () => function f () {
        f.self = this
        f.args = arguments
        return true
      },
      () => function f () {
        f.self = this
        f.args = arguments
        throw new Error('This condition fails with an error')
      }
    ]

    conditionCases.forEach(conditionGenerator => {
      selfVerifyCases.forEach(selfGenerator => {
        argsVerifyCases.forEach(argGenerator => {
          const condition = conditionGenerator()
          const self = selfGenerator()
          const args = argGenerator()
          it('works for ' + condition + ' - ' + self + ' - ' + args, function () {
            const subject = oneSubjectGenerator()
            const contractFunction = common.createCandidateContractFunction()
            const doctoredArgs = that.doctorArgs(args, contractFunction.bind(self))

            let outcome
            let metaError = false
            try {
              outcome = condition.apply()
            } catch (ignore) { // ConditionMetaError
              metaError = true
            }

            try {
              subject.verify(contractFunction, condition, self, doctoredArgs)
              outcome.must.be.truthy() // otherwise, we get an exception
              must(metaError).be.falsy()
            } catch (exc) {
              if (metaError) {
                // noinspection JSUnresolvedFunction
                conditionMetaErrorCommon.expectProperties(exc, ConditionMetaError, contractFunction, condition, self, doctoredArgs)
              } else { // ConditionViolation
                must(outcome).be.falsy()
                const extraProperty = doctoredArgs[args.length] // might not exist
                that.expectProperties(exc, subject.constructor, contractFunction, condition, self, args, extraProperty)
              }
            } finally {
              must(condition.self).equal(self)
              condition.args.must.be.truthy()
              isArguments(condition.args)
              // doctoredArgs might be arguments, or Array
              Array.prototype.slice.call(doctoredArgs).must.eql(Array.prototype.slice.call(condition.args))
              that.expectInvariants(subject)
            }
          })
        })
      })
    })
  })

  describe('#verifyAll()', function () {
    const conditionsCases = [
      () => [],
      () => [
        function f () {
          f.self = this
          f.args = arguments
          return false
        }
      ],
      () => [
        function f () {
          f.self = this
          f.args = arguments
          return true
        }
      ],
      () => [
        function f () {
          f.self = this
          f.args = arguments
          return {}
        }
      ],
      () => [
        function f1 () {
          f1.self = this
          f1.args = arguments
          return true
        },
        function f2 () {
          f2.self = this
          f2.args = arguments
          return true
        }
      ],
      () => [
        function f1 () {
          f1.self = this
          f1.args = arguments
          return true
        },
        function f2 () {
          f2.self = this
          f2.args = arguments
          return false
        },
        function f3 () {
          f3.self = this
          f3.args = arguments
          return true
        }
      ],
      () => [
        function f1 () {
          f1.self = this
          f1.args = arguments
          return true
        },
        function f3 () {
          f3.self = this
          f3.args = arguments
          throw new Error('This condition fails with an error')
        },
        function f3 () {
          f3.self = this
          f3.args = arguments
          return true
        }
      ]
    ]

    conditionsCases.forEach(conditionsGenerator => {
      selfVerifyCases.forEach(selfGenerator => {
        argsVerifyCases.forEach(argGenerator => {
          const conditions = conditionsGenerator()
          const self = selfGenerator()
          const args = argGenerator()
          it('works for ' + conditions + ' - ' + self + ' - ' + args, function () {
            const subject = oneSubjectGenerator()
            const contractFunction = common.createCandidateContractFunction()
            const doctoredArgs = that.doctorArgs(args, contractFunction.bind(self))

            let firstFailure
            let firstFailureIndex
            let metaError = false
            for (let i = 0; !firstFailure && i < conditions.length; i++) {
              try {
                const outcome = conditions[i].apply()
                if (!outcome) {
                  firstFailure = conditions[i]
                  firstFailureIndex = i
                }
              } catch (ignore) { // ConditionMetaError
                metaError = true
                firstFailure = conditions[i]
                firstFailureIndex = i
              }
            }

            try {
              // noinspection JSUnresolvedFunction
              subject.verifyAll(contractFunction, conditions, self, doctoredArgs)
              must(firstFailure).be.falsy() // any failure would give an exception
              must(metaError).be.falsy()
            } catch (exc) {
              conditions.length.must.be.at.least(1) // otherwise, there can be no failure
              firstFailure.must.be.truthy() // metaError or a false condition
              if (metaError) {
                conditionMetaErrorCommon.expectProperties(exc, ConditionMetaError, contractFunction, firstFailure, self, doctoredArgs)
              } else {
                const extraProperty = doctoredArgs[args.length] // might not exist
                that.expectProperties(exc, subject.constructor, contractFunction, firstFailure, self, args, extraProperty)
              }
            } finally {
              // evaluates all conditions up until the first failure with the given self and arguments
              for (let j = 0; j <= firstFailureIndex; j++) {
                must(conditions[j].self).equal(self)
                const appliedArgs = conditions[j].args
                appliedArgs.must.be.truthy()
                isArguments(appliedArgs)
                if (!args) {
                  appliedArgs.must.be.empty()
                } else {
                  // doctoredArgs might be arguments, or Array
                  Array.prototype.slice.call(doctoredArgs).must.eql(Array.prototype.slice.call(appliedArgs))
                }
              }
              // does not evaluate conditions after the first failure
              for (let j = firstFailureIndex + 1; j < conditions.length; j++) {
                must(conditions[j].self).be.falsy()
                must(conditions[j].args).be.falsy()
              }
              that.expectInvariants(subject)
            }
          })
        })
      })
    })
  })
}

// TODO test verifyPromise and verifyAllPromise

const test = {
  selfVerifyCases: selfVerifyCases,
  argsVerifyCases: argsVerifyCases,
  generatePrototypeMethodsDescriptions: generatePrototypeMethodsDescriptions,
  expectInvariants: expectInvariants,
  expectProperties: expectProperties,
  expectConstructorPost: expectConstructorPost,
  doctorArgs: doctorArgs
}
Object.setPrototypeOf(test, common)

module.exports = test
<commit_msg>Change TODO in MUDO<commit_after>/*
 Copyright 2016 - 2018 by Jan Dockx

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

/* eslint-env mocha */

'use strict'

const testUtil = require('../_util/testUtil')
const common = require('./ConditionErrorCommon')
const ConditionMetaError = require('../../lib/IV/ConditionMetaError')
const ConditionViolation = require('../../lib/IV/ConditionViolation')
const conditionMetaErrorCommon = require('./ConditionMetaErrorCommon')
const must = require('must')

function isArguments (o) {
  const str = '' + o
  str.must.equal('[object Arguments]')
}

const selfVerifyCases = [
  function () { return undefined },
  function () { return null },
  function () { return {} }
]

function args () { return arguments }

const argsVerifyCases = [
  function () { return args() },
  function () { return args('an argument') },
  function () { return args('an argument', 'another argument') },
  function () { return ['an argument in an array'] }
]

function expectInvariants (subject) {
  subject.must.be.an.instanceof(ConditionViolation)
  common.expectInvariants(subject)
  testUtil.expectFrozenPropertyOnAPrototype(subject, 'verify')
  subject.verify.must.be.a.function()
  testUtil.expectFrozenPropertyOnAPrototype(subject, 'verifyAll')
  // noinspection JSUnresolvedVariable
  subject.verifyAll.must.be.a.function()
}

// noinspection ParameterNamingConventionJS
function expectProperties (exception, Type, contractFunction, condition, self, args) {
  common.expectProperties.apply(undefined, arguments)
  exception.must.be.frozen()
}

function expectConstructorPost (result, contractFunction, condition, self, args) {
  // noinspection JSUnresolvedVariable
  common.expectConstructorPost(result, contractFunction, condition, self, args, result._rawStack)
  common.expectProperties.call(undefined, result, ConditionViolation, contractFunction, condition, self, args)
  // not frozen yet
}

// noinspection JSUnusedLocalSymbols
function doctorArgs (args, boundContractFunction) {
  return args
}

// noinspection FunctionNamingConventionJS
function generatePrototypeMethodsDescriptions (oneSubjectGenerator, allSubjectGenerators) {
  common.generatePrototypeMethodsDescriptions(oneSubjectGenerator, allSubjectGenerators)

  const that = this

  describe('#verify()', function () {
    const conditionCases = [
      () => function f () {
        f.self = this
        f.args = arguments
        // no return
      },
      () => function f () {
        f.self = this
        f.args = arguments
        return false
      },
      () => function f () {
        f.self = this
        f.args = arguments
        return true
      },
      () => function f () {
        f.self = this
        f.args = arguments
        throw new Error('This condition fails with an error')
      }
    ]

    conditionCases.forEach(conditionGenerator => {
      selfVerifyCases.forEach(selfGenerator => {
        argsVerifyCases.forEach(argGenerator => {
          const condition = conditionGenerator()
          const self = selfGenerator()
          const args = argGenerator()
          it('works for ' + condition + ' - ' + self + ' - ' + args, function () {
            const subject = oneSubjectGenerator()
            const contractFunction = common.createCandidateContractFunction()
            const doctoredArgs = that.doctorArgs(args, contractFunction.bind(self))

            let outcome
            let metaError = false
            try {
              outcome = condition.apply()
            } catch (ignore) { // ConditionMetaError
              metaError = true
            }

            try {
              subject.verify(contractFunction, condition, self, doctoredArgs)
              outcome.must.be.truthy() // otherwise, we get an exception
              must(metaError).be.falsy()
            } catch (exc) {
              if (metaError) {
                // noinspection JSUnresolvedFunction
                conditionMetaErrorCommon.expectProperties(exc, ConditionMetaError, contractFunction, condition, self, doctoredArgs)
              } else { // ConditionViolation
                must(outcome).be.falsy()
                const extraProperty = doctoredArgs[args.length] // might not exist
                that.expectProperties(exc, subject.constructor, contractFunction, condition, self, args, extraProperty)
              }
            } finally {
              must(condition.self).equal(self)
              condition.args.must.be.truthy()
              isArguments(condition.args)
              // doctoredArgs might be arguments, or Array
              Array.prototype.slice.call(doctoredArgs).must.eql(Array.prototype.slice.call(condition.args))
              that.expectInvariants(subject)
            }
          })
        })
      })
    })
  })

  describe('#verifyAll()', function () {
    const conditionsCases = [
      () => [],
      () => [
        function f () {
          f.self = this
          f.args = arguments
          return false
        }
      ],
      () => [
        function f () {
          f.self = this
          f.args = arguments
          return true
        }
      ],
      () => [
        function f () {
          f.self = this
          f.args = arguments
          return {}
        }
      ],
      () => [
        function f1 () {
          f1.self = this
          f1.args = arguments
          return true
        },
        function f2 () {
          f2.self = this
          f2.args = arguments
          return true
        }
      ],
      () => [
        function f1 () {
          f1.self = this
          f1.args = arguments
          return true
        },
        function f2 () {
          f2.self = this
          f2.args = arguments
          return false
        },
        function f3 () {
          f3.self = this
          f3.args = arguments
          return true
        }
      ],
      () => [
        function f1 () {
          f1.self = this
          f1.args = arguments
          return true
        },
        function f3 () {
          f3.self = this
          f3.args = arguments
          throw new Error('This condition fails with an error')
        },
        function f3 () {
          f3.self = this
          f3.args = arguments
          return true
        }
      ]
    ]

    conditionsCases.forEach(conditionsGenerator => {
      selfVerifyCases.forEach(selfGenerator => {
        argsVerifyCases.forEach(argGenerator => {
          const conditions = conditionsGenerator()
          const self = selfGenerator()
          const args = argGenerator()
          it('works for ' + conditions + ' - ' + self + ' - ' + args, function () {
            const subject = oneSubjectGenerator()
            const contractFunction = common.createCandidateContractFunction()
            const doctoredArgs = that.doctorArgs(args, contractFunction.bind(self))

            let firstFailure
            let firstFailureIndex
            let metaError = false
            for (let i = 0; !firstFailure && i < conditions.length; i++) {
              try {
                const outcome = conditions[i].apply()
                if (!outcome) {
                  firstFailure = conditions[i]
                  firstFailureIndex = i
                }
              } catch (ignore) { // ConditionMetaError
                metaError = true
                firstFailure = conditions[i]
                firstFailureIndex = i
              }
            }

            try {
              // noinspection JSUnresolvedFunction
              subject.verifyAll(contractFunction, conditions, self, doctoredArgs)
              must(firstFailure).be.falsy() // any failure would give an exception
              must(metaError).be.falsy()
            } catch (exc) {
              conditions.length.must.be.at.least(1) // otherwise, there can be no failure
              firstFailure.must.be.truthy() // metaError or a false condition
              if (metaError) {
                conditionMetaErrorCommon.expectProperties(exc, ConditionMetaError, contractFunction, firstFailure, self, doctoredArgs)
              } else {
                const extraProperty = doctoredArgs[args.length] // might not exist
                that.expectProperties(exc, subject.constructor, contractFunction, firstFailure, self, args, extraProperty)
              }
            } finally {
              // evaluates all conditions up until the first failure with the given self and arguments
              for (let j = 0; j <= firstFailureIndex; j++) {
                must(conditions[j].self).equal(self)
                const appliedArgs = conditions[j].args
                appliedArgs.must.be.truthy()
                isArguments(appliedArgs)
                if (!args) {
                  appliedArgs.must.be.empty()
                } else {
                  // doctoredArgs might be arguments, or Array
                  Array.prototype.slice.call(doctoredArgs).must.eql(Array.prototype.slice.call(appliedArgs))
                }
              }
              // does not evaluate conditions after the first failure
              for (let j = firstFailureIndex + 1; j < conditions.length; j++) {
                must(conditions[j].self).be.falsy()
                must(conditions[j].args).be.falsy()
              }
              that.expectInvariants(subject)
            }
          })
        })
      })
    })
  })
}

// MUDO test verifyPromise and verifyAllPromise (now covered indirectly via PromiseContractFunctionTest)

const test = {
  selfVerifyCases: selfVerifyCases,
  argsVerifyCases: argsVerifyCases,
  generatePrototypeMethodsDescriptions: generatePrototypeMethodsDescriptions,
  expectInvariants: expectInvariants,
  expectProperties: expectProperties,
  expectConstructorPost: expectConstructorPost,
  doctorArgs: doctorArgs
}
Object.setPrototypeOf(test, common)

module.exports = test
<|endoftext|>


<commit_before>"use strict";

var Class = require("nodeclass").Class,
    Page = require("../../../lib/client/Page.class.js");

//@TODO use Page.define
/*
var PageExample = Page.define({

    /**
     * Exposes protected ._getParams()
     * @return {object}
     */
    /*
    getParams: function () {
        return this._getParams();
    },

    /**
     * Exposes ._isDisposed()
     * @return {boolean}
     */
/*
    isDisposed: function () {
        return this._isDisposed();
    },

    $template: "

"

});
*/
var PageExample = new Class({

    Extends: Page,

    /**
     * Exposes protected ._getParams()
     * @return {object}
     */
    getParams: function () {
        return this.Super._getParams();
    },

    /**
     * Exposes ._isDisposed()
     * @return {boolean}
     */
    isDisposed: function () {
        return this.Super._getIsDisposed();
    },

    $template: "

"

});

module.exports = PageExample;<commit_msg>- Tidy<commit_after>"use strict";

var Class = require("nodeclass").Class,
    Page = require("../../../lib/client/Page.class.js");

var PageExample = new Class({

    Extends: Page,

    /**
     * Exposes protected ._getParams()
     * @return {object}
     */
    getParams: function () {
        return this.Super._getParams();
    },

    /**
     * Exposes ._isDisposed()
     * @return {boolean}
     */
    isDisposed: function () {
        return this.Super._getIsDisposed();
    },

    $template: "

"

});

module.exports = PageExample;<|endoftext|>


<commit_before>/**
 * entry_HOMEPAGE.js
 *
 * Module for loading styles and scripts related to the home page only
 *
 */

var $ = require( "jquery" ); // require jQuery

require( "./homepage.scss" ); // styles for the homepage only

// Wait for the DOM to be ready before loading in JSON
document.addEventListener( "DOMContentLoaded", function( event ) {

  /*
   * ==================================================================
   * LOOK FOR THE FIRST 11 POSTS VIA THE WP REST API AND PLACE THEM ON * THE HOME PAGE ON A CERTAIN WAY
   * ==================================================================
   */

  /*
   * Grab the first 10 single posts from the WordPress API & sort them
   * by date.
   */
  var getPostsAPI = "/wp-json/posts?filter[orderby]=date&filter[posts_per_page]=11";

  /*
   * Load in post content data with $.getJSON()
   * Refer to this data as "posts" inside the $.getJSON call
   */
  $.getJSON( getPostsAPI ).done( function( posts ) {

    // var reference to
 on the home page
    var articleSection = document.getElementById( "all-articles" ),

      // Create document fragment to batch-load content onto the page
      sectionDocFrag = document.createDocumentFragment();

    for( var key in posts ) {

      // jQuery-styled single var pattern
      var postImage, postLink, postTitle, postExcerpt, postCategory,
          articlePost = document.createElement( "article" ),
          articleHeader = document.createElement( "h2" ),
          articleExcerpt = document.createElement( "p" ),
          articleLink = document.createElement( "a" ),
          articleImage = document.createElement( "img" ),
          imageDiv = document.createElement( "div" ),
          categoryDiv = document.createElement( "div" );

      // SET UP THE
 TAG!!!!

      // Check if we're working with the first post
      if( posts[key] == posts[0] ) {
        /*
         * If it's the first post, apply the
         * "first-homepage-post-snippet" class to the
 tag
         */
        articlePost.setAttribute( "class", "first-homepage-post-snippet" );
      } else {
        /*
         * If it's NOT the first post, apply the
         * "homepage-post-snippet" class to the
 tag
         */
        articlePost.setAttribute( "class", "homepage-post-snippet" );
      }
      // STOP
 TAG SETUP!!!!

      // SET UP SINGLE BLOG POST IMAGES!!!!

      /*
       * Featured images are defined by "Featured Image" section of a
       * single WordPress post's page. If it's not defined, a
       * default image is loaded via the Default featured image
       * WordPress plugin.
       */
      postImage = posts[key].featured_image["source"];

      // Add styles and a "src" attribute to the image
      $( articleImage ).attr({
        "src": postImage,
        "class": "post-pic post-pic-border"
      });

      // Load post image in a

      imageDiv.appendChild( articleImage );

      // STOP SINGLE BLOG POST IMAGES SETUP!!!!

      // SET UP SINGLE BLOG LINK & HEADER!!!!

      // Get post title link
      postLink = posts[key].link;

      // Get post title copy
      postTitle = posts[key].title;

      // Set the article link's "href" to be the post link
      $(articleLink).attr({
        "href": postLink,
        class: "post-link"
      });

      // Load post title copy in the  tag
      articleLink.innerHTML = postTitle;

      // Load link into the post header
      articleHeader.appendChild( articleLink );

      articleHeader.setAttribute("class", "post-link-homepage");

      // STOP SINGLE BLOG LINK & HEADER SETUP!!!!

      // SET UP SINGLE BLOG POST EXCERPT!!!!

      // Get post excerpt copy
      postExcerpt = posts[key].excerpt;

      // Load post excerpt copy in the
 tag
      articleExcerpt.innerHTML = postExcerpt;

      // STOP SINGLE BLOG POST EXCERPT SETUP!!!!

      /*
       * APPEND EVERYTHING WE HAVE AT THIS POINT TO THE

       *
       * We have all the post snippet elements...EXCEPT for the
       * category. Append those elements to the
 tag.
       */

      // First, append the post image to the
...
      articlePost.appendChild( imageDiv );

      // Second, append the post header to the
...
      articlePost.appendChild( articleHeader );

      // Third, append the post excerpt to the
...
      articlePost.appendChild( articleExcerpt );

      /*
       * SET UP THE CATEGORY !!!!
       *
       * The category name object is nested deeper in the WP-API than
       * the other info, so we have to do a an inner for...in loop.
       * This code needs to run last; otherwise, it breaks the process
       * of grabbing certain data from the WP-API for all the posts.
       */

      // Grab the "category" value in the WP-API
      postCategory = posts[key].terms["category"];

      // Loop through the category object
      for ( var key in postCategory ) {

        // Find category name and put it in the "categoryDiv" element
        categoryDiv.innerHTML = postCategory[key].name;

        // Give "categoryDiv" element a class name of "category-name"
        categoryDiv.setAttribute( "class", "category-name" );

        // Use $.prepend() to put "categoryDiv" at the TOP of

        $( articlePost ).prepend( categoryDiv );
      }

      // STOP CATEGORY SETUP !!!!

      /*
       * Load article with title, image, excerpt and category into the
       * document fragment
       */
      sectionDocFrag.appendChild( articlePost );

    } // end for...in loop

    /*
     * Exit loop, then load the document fragment with all the content
     * into the "all-articles" element that's already on the page
     */
    articleSection.appendChild( sectionDocFrag );

  }); // end $.getJSON()

}); // end addEventListener<commit_msg>update comments<commit_after>/**
 * entry_HOMEPAGE.js
 *
 * Module for loading styles and scripts related to the home page only
 *
 */

var $ = require( "jquery" ); // require jQuery

require( "./homepage.scss" ); // styles for the homepage only

// Wait for the DOM to be ready before loading in JSON
document.addEventListener( "DOMContentLoaded", function( event ) {

  /*
   * ==================================================================
   * LOOK FOR THE FIRST 11 POSTS VIA THE WP REST API AND PLACE THEM ON * THE HOME PAGE ON A CERTAIN WAY
   * ==================================================================
   */

  /*
   * Grab the first 10 single posts from the WordPress API & sort them
   * by date.
   */
  var getPostsAPI = "/wp-json/posts?filter[orderby]=date&filter[posts_per_page]=11";

  /*
   * Load in post content data with $.getJSON()
   * Refer to this data as "posts" inside the $.getJSON call
   */
  $.getJSON( getPostsAPI ).done( function( posts ) {

    // var reference to
 on the home page
    var articleSection = document.getElementById( "all-articles" ),

      // Create document fragment to batch-load content onto the page
      sectionDocFrag = document.createDocumentFragment();

    for( var key in posts ) {

      // jQuery-styled single var pattern
      var postImage, postLink, postTitle, postExcerpt, postCategory,
          articlePost = document.createElement( "article" ),
          articleHeader = document.createElement( "h2" ),
          articleExcerpt = document.createElement( "p" ),
          articleLink = document.createElement( "a" ),
          articleImage = document.createElement( "img" ),
          imageDiv = document.createElement( "div" ),
          categoryDiv = document.createElement( "div" );

      // SET UP THE
 TAG!!!!

      // Check if we're working with the first post
      if( posts[key] == posts[0] ) {
        /*
         * If it's the first post, apply the
         * "first-homepage-post-snippet" class to the
 tag
         */
        articlePost.setAttribute( "class", "first-homepage-post-snippet" );
      } else {
        /*
         * If it's NOT the first post, apply the
         * "homepage-post-snippet" class to the
 tag
         */
        articlePost.setAttribute( "class", "homepage-post-snippet" );
      }
      // STOP
 TAG SETUP!!!!

      // SET UP SINGLE BLOG POST IMAGES!!!!

      /*
       * Featured images are defined by "Featured Image" section of a
       * single WordPress post's page. If it's not defined, a
       * default image is loaded via the Default featured image
       * WordPress plugin.
       */
      postImage = posts[key].featured_image["source"];

      // Add styles and a "src" attribute to the image
      $( articleImage ).attr({
        "src": postImage,
        "class": "post-pic post-pic-border"
      });

      // Load post image in a

      imageDiv.appendChild( articleImage );

      // STOP SINGLE BLOG POST IMAGES SETUP!!!!

      // SET UP SINGLE BLOG LINK & HEADER!!!!

      // Get post title link
      postLink = posts[key].link;

      // Get post title copy
      postTitle = posts[key].title;

      // Set the article link's "href" to be the post link
      $(articleLink).attr({
        "href": postLink,
        class: "post-link"
      });

      // Load post title copy in the  tag
      articleLink.innerHTML = postTitle;

      // Load link into the post header
      articleHeader.appendChild( articleLink );

      articleHeader.setAttribute("class", "post-link-homepage");

      // STOP SINGLE BLOG LINK & HEADER SETUP!!!!

      // SET UP SINGLE BLOG POST EXCERPT!!!!

      // Get post excerpt copy
      postExcerpt = posts[key].excerpt;

      // Load post excerpt copy in the
 tag
      articleExcerpt.innerHTML = postExcerpt;

      // STOP SINGLE BLOG POST EXCERPT SETUP!!!!

      /*
       * APPEND EVERYTHING WE HAVE AT THIS POINT TO THE

       *
       * We have all the post snippet elements...EXCEPT for the
       * category. Append those elements to the
 tag.
       */

      // First, append the post image to the
...
      articlePost.appendChild( imageDiv );

      // Second, append the post header to the
...
      articlePost.appendChild( articleHeader );

      // Third, append the post excerpt to the
.
      articlePost.appendChild( articleExcerpt );

      /*
       * SET UP THE CATEGORY !!!!
       *
       * The category name object is nested deeper in the WP-API than
       * the other info, so we have to do a an inner for...in loop.
       * This code needs to run last; otherwise, it breaks the process
       * of grabbing certain data from the WP-API for all the posts.
       */

      // Grab the "category" value in the WP-API
      postCategory = posts[key].terms["category"];

      // Loop through the category object
      for ( var key in postCategory ) {

        // Find category name and put it in the "categoryDiv" element
        categoryDiv.innerHTML = postCategory[key].name;

        // Give "categoryDiv" element a class name of "category-name"
        categoryDiv.setAttribute( "class", "category-name" );

        // Use $.prepend() to put "categoryDiv" at the TOP of

        $( articlePost ).prepend( categoryDiv );
      }

      // STOP CATEGORY SETUP !!!!

      /*
       * Load article with title, image, excerpt and category into the
       * document fragment
       */
      sectionDocFrag.appendChild( articlePost );

    } // end for...in loop

    /*
     * Exit loop, then load the document fragment with all the content
     * into the "all-articles" element that's already on the page
     */
    articleSection.appendChild( sectionDocFrag );

  }); // end $.getJSON()

}); // end addEventListener<|endoftext|>