<commit_before>import Inferno from '../../../../src';
import get from '../../../tools/get';

const {
    createElement
} = Inferno.TemplateFactory;

describe('DOM element tests3 (no-jsx)', () => {
    let container;

    beforeEach(() => {
        container = document.createElement('div');
    });

    afterEach(() => {
        Inferno.render(null, container);
    });

    describe('should render text then update to an array of text nodes', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: 'Hello'
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello');
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello');
            Inferno.render(template(null), container);
            expect(container.firstChild.innerHTML).to.equal('');

            const spanWithChildren = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: {
						tag: 'example',
						attrs: {id: 'foo' },
						children: {
								tag:'span',
								text: 'Hello'
							}
						}
                };
            });
            Inferno.render(template(spanWithChildren()), container);
            expect(container.firstChild.innerHTML).to.equal('<example id="foo">Hello</example>');
        });

        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');

            const span1 = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello', null, '!']
                };
            });
            Inferno.render(template(span1()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello!');

			// Whitespace issue!
            const span2 = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello', null, '  !  ']
                };
            });
            Inferno.render(template(span1()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello  !  ');

        });
    });

    describe('should render an array of text nodes then update to a single text node', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');
        });
        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: 'Hello'
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello');
        });
    });

    describe('should update and array of text nodes to another array of text nodes', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World');

            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('');
        });

        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');

            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('');

        });
    });

    describe('should update and array of text nodes to another array of text nodes #2', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');

            const span1 = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: [null, null, null, null]
                };
            });
            Inferno.render(template(span1()), container);
            expect(container.firstChild.innerHTML).to.equal('');

			 const spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: ['Hello ', null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello ');

        });

        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World');

			let spanish;

			 spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: ['Hello ', null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello ');

             spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: ['Hello ', null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello ');

            spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: [null, null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

            spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: [undefined, undefined]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

            spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: [undefined, null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

             spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: null
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

        });
    });

    describe('should set className on root node, and update an node with dynamic attributes on static child', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: {
                tag: 'div',
                attrs: {
                    class: 'hello!'
                },
                children: {
                    tag: 'span',
                    attrs: {
                        id: child
                    }
                }
            }
        }));

        it('first render (creation)', () => {
            Inferno.render(template('id#1'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template('id#3'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('

');

        });
        it('second render - (update)', () => {
            Inferno.render(template('id#2'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template('id#4'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template(null), container);
            expect(container.firstChild.innerHTML).to.equal('

');

        });
    });

    describe('should update if different static namespaces', () => {
        const template = Inferno.createTemplate((val) => ({
            tag: 'div',
            attrs: {
                xmlns: 'testing',
                id: val
            }
        }));

        it('first render (creation)', () => {
            Inferno.render(template("testing"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
            Inferno.render(template("testing123"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
        });
        it('second render - (update)', () => {
            Inferno.render(template("undefined"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
            Inferno.render(template("undefined"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
        });
    });

    describe('should properly render input download attribute', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                download: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template(false), container);
            expect(container.firstChild.getAttribute('download')).to.be.null;
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
            Inferno.render(template(false), container);
            expect(container.firstChild.getAttribute('download')).to.be.null;
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
    });

    describe('should properly render scope attribute', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                scope: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template('scope'), container);
            expect(container.firstChild.getAttribute('scope')).to.eql('scope');
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(), container);
            expect(container.firstChild.getAttribute('scope')).to.be.null;
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(false), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template('true'), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template('false'), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(null), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
    });

    describe('should properly render HTMLL5 data-* attribute', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                data: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template('val'), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(null), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

        });
    });

    describe('should properly render value property', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                value: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template('val'), container);
            expect(container.firstChild.value).to.eql('val');
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(container.firstChild.value).to.eql(true);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
    });

});<commit_msg>one last one<commit_after>import Inferno from '../../../../src';
import get from '../../../tools/get';

const {
    createElement
} = Inferno.TemplateFactory;

describe('DOM element tests3 (no-jsx)', () => {
    let container;

    beforeEach(() => {
        container = document.createElement('div');
    });

    afterEach(() => {
        Inferno.render(null, container);
    });

    describe('should render text then update to an array of text nodes', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: 'Hello'
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello');
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello');
            Inferno.render(template(null), container);
            expect(container.firstChild.innerHTML).to.equal('');

            const spanWithChildren = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: {
						tag: 'example',
						attrs: {id: 'foo' },
						children: {
								tag:'span',
								text: 'Hello'
							}
						}
                };
            });
            Inferno.render(template(spanWithChildren()), container);
            expect(container.firstChild.innerHTML).to.equal('<example id="foo">Hello</example>');
        });

        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');

            const span1 = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello', null, '!']
                };
            });
            Inferno.render(template(span1()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello!');

			// Whitespace issue!
            const span2 = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello', null, '  !  ']
                };
            });
            Inferno.render(template(span1()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello  !  ');

        });
    });

    describe('should render an array of text nodes then update to a single text node', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');
        });
        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: 'Hello'
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello');
        });
    });

    describe('should update and array of text nodes to another array of text nodes', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World');

            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('');
        });

        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');

            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('');

        });
    });

    describe('should update and array of text nodes to another array of text nodes #2', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: child
        }));

        it('first render (creation)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World', '!']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World!');

            const span1 = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: [null, null, null, null]
                };
            });
            Inferno.render(template(span1()), container);
            expect(container.firstChild.innerHTML).to.equal('');

			 const spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: ['Hello ', null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello ');

        });

        it('second render - (update)', () => {
            const span = Inferno.createTemplate(function() {
                return {
                    tag: 'span',
                    children: ['Hello ', 'World']
                };
            });
            Inferno.render(template(span()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello World');

			let spanish;

			 spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: ['Hello ', null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello ');

             spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: ['Hello ', null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('Hello ');

            spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: [null, null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

            spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: [undefined, undefined]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

            spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: [undefined, null]
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

             spanish = Inferno.createTemplate(function() {
                return {
                    tag: 'b',
                    children: null
                };
            });
            Inferno.render(template(spanish()), container);
            expect(container.firstChild.innerHTML).to.equal('');

        });
    });

    describe('should set className on root node, and update an node with dynamic attributes on static child', () => {
        const template = Inferno.createTemplate((child) => ({
            tag: 'div',
            children: {
                tag: 'div',
                attrs: {
                    class: 'hello!'
                },
                children: {
                    tag: 'span',
                    attrs: {
                        id: child
                    }
                }
            }
        }));

        it('first render (creation)', () => {
            Inferno.render(template('id#1'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template('id#3'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('

');

        });
        it('second render - (update)', () => {
            Inferno.render(template('id#2'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template('id#4'), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template(), container);
            expect(container.firstChild.innerHTML).to.equal('

');
            Inferno.render(template(null), container);
            expect(container.firstChild.innerHTML).to.equal('

');

        });
    });

    describe('should update if different static namespaces', () => {
        const template = Inferno.createTemplate((val) => ({
            tag: 'div',
            attrs: {
                xmlns: 'testing',
                id: val
            }
        }));

        it('first render (creation)', () => {
            Inferno.render(template("testing"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
            Inferno.render(template("testing123"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
        });
        it('second render - (update)', () => {
            Inferno.render(template("undefined"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
            Inferno.render(template("undefined"), container);
            expect(container.innerHTML).to.equal('

');
            expect(container.firstChild.namespaceURI).to.eql("testing");
        });
    });

    describe('should properly render input download attribute', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                download: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template(false), container);
            expect(container.firstChild.getAttribute('download')).to.be.null;
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
            Inferno.render(template(false), container);
            expect(container.firstChild.getAttribute('download')).to.be.null;
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
    });

    describe('should properly render scope attribute', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                scope: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template('scope'), container);
            expect(container.firstChild.getAttribute('scope')).to.eql('scope');
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(), container);
            expect(container.firstChild.getAttribute('scope')).to.be.null;
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(false), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template('true'), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template('false'), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(null), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
    });

    describe('should properly render HTMLL5 data-* attribute', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                data: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template('val'), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(null), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

            Inferno.render(template(true), container);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );

        });
    });

    describe('should properly render value property', () => {
        let template = Inferno.createTemplate((val1) =>
            createElement('div', {
                value: val1
            })
        );

        it('Initial render (creation)', () => {
            Inferno.render(template('val'), container);
            expect(container.firstChild.value).to.eql('val');
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
        it('Second render (update)', () => {
            Inferno.render(template(true), container);
            expect(container.firstChild.value).to.eql(true);
            expect(
                container.innerHTML
            ).to.equal(
                '

'
            );
        });
    });

    describe('should properly render dynamic child with null and number', () => {

 const templateFunc = (child) => ({
                tag: 'div',
                children: child
            });
        const template = Inferno.createTemplate(templateFunc)
        );

        it('Initial render (creation)', () => {
            Inferno.render(template([1, 2, null]), container);
            expect(
                container.innerHTML
            ).to.equal(
                '
12
'
            );
        });
    });

});<|endoftext|>


<commit_before>'use strict';

var Node = require('../node');

var TYPE = 'gravity';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY), // "populated places"
    target: Node.PARAM.NODE(Node.GEOMETRY.POINT), // "malls"
    weight_column: Node.PARAM.STRING(),
    weight_threshold: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(),-10e307),
    pop_column: Node.PARAM.STRING(),
    max_distance: Node.PARAM.NUMBER(), // meters
    target_id: Node.PARAM.NUMBER() // the "mall" to be studied
};

var Gravity = Node.create(TYPE, PARAMS, {cache: true, version: 1});

module.exports = Gravity;
module.exports.TYPE = TYPE;
module.exports.PARAMS = PARAMS;

var gravityTemplate = Node.template([
    'WITH ',
    ' raw_s as({{=it.sourceQuery}}),',
    ' raw_t as({{=it.targetQuery}}),',
    ' s as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.p}},0)::numeric) as p',
        ' FROM raw_s',
    '),',
    ' t as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.w}},0)::numeric) as w',
        ' FROM raw_t',
    ')',
    'SELECT ',
    ' g.source_id as cartodb_id,',
    ' g.the_geom,',
    ' ST_transform(g.the_geom, 3857) as the_geom_webmercator,',
    ' g.h as patronage_prob,',
    ' g.hpop patronaging_pop,',
    ' g.dist as dist_to_target ',
    'FROM ',
    ' t,',
    ' s,',
    ' CDB_Gravity(t.id, t.g, t.w, s.id, s.g, s.p,',
    '  {{=it.targetID}}::bigint, {{=it.r}}::integer, {{=it.wt}}::numeric) g'
].join('\n'));

Gravity.prototype.sql = function(){
    return gravityTemplate({
        sourceQuery: this.source.getQuery(),
        targetQuery: this.target.getQuery(),
        targetID: this.target_id,
        w: this.weight_column,
        wt: this.weight_threshold,
        p: this.pop_column,
        r: this.max_distance
    });
};
<commit_msg>add cdb_crankshaft schema<commit_after>'use strict';

var Node = require('../node');

var TYPE = 'gravity';

var PARAMS = {
    source: Node.PARAM.NODE(Node.GEOMETRY.ANY), // "populated places"
    target: Node.PARAM.NODE(Node.GEOMETRY.POINT), // "malls"
    weight_column: Node.PARAM.STRING(),
    weight_threshold: Node.PARAM.NULLABLE(Node.PARAM.NUMBER(),-10e307),
    pop_column: Node.PARAM.STRING(),
    max_distance: Node.PARAM.NUMBER(), // meters
    target_id: Node.PARAM.NUMBER() // the "mall" to be studied
};

var Gravity = Node.create(TYPE, PARAMS, {cache: true, version: 1});

module.exports = Gravity;
module.exports.TYPE = TYPE;
module.exports.PARAMS = PARAMS;

var gravityTemplate = Node.template([
    'WITH ',
    ' raw_s as({{=it.sourceQuery}}),',
    ' raw_t as({{=it.targetQuery}}),',
    ' s as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.p}},0)::numeric) as p',
        ' FROM raw_s',
    '),',
    ' t as(',
        'SELECT',
        ' array_agg(cartodb_id::bigint) as id,',
        ' array_agg(the_geom) as g,',
        ' array_agg(coalesce({{=it.w}},0)::numeric) as w',
        ' FROM raw_t',
    ')',
    'SELECT ',
    ' g.source_id as cartodb_id,',
    ' g.the_geom,',
    ' ST_transform(g.the_geom, 3857) as the_geom_webmercator,',
    ' g.h as patronage_prob,',
    ' g.hpop patronaging_pop,',
    ' g.dist as dist_to_target ',
    'FROM ',
    ' t,',
    ' s,',
    ' cdb_crankshaft.CDB_Gravity(t.id, t.g, t.w, s.id, s.g, s.p,',
    '  {{=it.targetID}}::bigint, {{=it.r}}::integer, {{=it.wt}}::numeric) g'
].join('\n'));

Gravity.prototype.sql = function(){
    return gravityTemplate({
        sourceQuery: this.source.getQuery(),
        targetQuery: this.target.getQuery(),
        targetID: this.target_id,
        w: this.weight_column,
        wt: this.weight_threshold,
        p: this.pop_column,
        r: this.max_distance
    });
};
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var Buffer = require('buffer').Buffer;

var TimeSeriesCluster = require('../lib/time-series-cluster.js');

var KILOBYTE = 1024;
var REQUEST_BODY = TimeSeriesCluster.buildString(128 * KILOBYTE);
var REQUEST_BODY_CHUNKS = [
    new Buffer(REQUEST_BODY),
    new Buffer(REQUEST_BODY),
    new Buffer(REQUEST_BODY),
    new Buffer(REQUEST_BODY)
];

TimeSeriesCluster.test('constant low volume 512kb traffic', {
    clusterOptions: {},
    buckets: [
        25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25
    ],
    clientTimeout: 250,
    endpointToRequest: 'streaming-echo-endpoint',
    // requestBody: new Buffer(TimeSeriesCluster.buildString(512 * KILOBYTE)),
    requestBodyChunks: REQUEST_BODY_CHUNKS,

    numBatchesInBucket: 50,
    clientBatchDelay: 400,
    clientRequestsPerBatch: 10
}, function t(cluster, assert) {
    cluster.logger.whitelist('info', 'error for timed out outgoing response');
    cluster.logger.whitelist('info', 'forwarding expected error frame');
    cluster.logger.whitelist('info', 'expected error while forwarding');
    cluster.logger.whitelist('info', 'OutResponse.send() after inreq timed out');
    cluster.logger.whitelist('warn', 'forwarding error frame');
    cluster.logger.whitelist('warn', 'mismatched conn.onReqDone');

    cluster.printBatches();

    // cluster.sendRequests(onResults);
    cluster.sendStreamingRequests(onResults);

    var shouldTakeHeaps = false;
    if (shouldTakeHeaps) {
        cluster.takeHeaps(20, 40, 60);
    }

    function onResults(err, results) {
        assert.ifError(err);

        // Skip bucket 0 because JIT warmup
        for (var i = 1; i < cluster.buckets.length; i++) {
            cluster.assertRange(assert, {
                index: i,
                value: results[i].errorCount,
                min: 0,
                max: 50,
                description: ' reqs with timeout of ' + cluster.buckets[i]
            });
            cluster.assertRange(assert, {
                index: i,
                value: results[i].latency.p95,
                min: 100,
                max: 140,
                description: ' p95 of requests '
            });
            cluster.assertRange(assert, {
                index: i,
                value: results[i].processMetrics.heapTotal,
                min: 50,
                max: 90,
                description: ' heap size of process '
            });
            cluster.assertRange(assert, {
                index: i,
                value: results[i].processMetrics.rss,
                min: 300,
                max: 420,
                description: ' RSS of process '
            });
        }

        assert.end();
    }
});
<commit_msg>joshua is very nit picky<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

var Buffer = require('buffer').Buffer;

var TimeSeriesCluster = require('../lib/time-series-cluster.js');

var KILOBYTE = 1024;
var REQUEST_BODY = TimeSeriesCluster.buildString(128 * KILOBYTE);
var REQUEST_BODY_CHUNKS = [
    new Buffer(REQUEST_BODY),
    new Buffer(REQUEST_BODY),
    new Buffer(REQUEST_BODY),
    new Buffer(REQUEST_BODY)
];

TimeSeriesCluster.test('constant low volume 512KiB traffic', {
    clusterOptions: {},
    buckets: [
        25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25
    ],
    clientTimeout: 250,
    endpointToRequest: 'streaming-echo-endpoint',
    // requestBody: new Buffer(TimeSeriesCluster.buildString(512 * KILOBYTE)),
    requestBodyChunks: REQUEST_BODY_CHUNKS,

    numBatchesInBucket: 50,
    clientBatchDelay: 400,
    clientRequestsPerBatch: 10
}, function t(cluster, assert) {
    cluster.logger.whitelist('info', 'error for timed out outgoing response');
    cluster.logger.whitelist('info', 'forwarding expected error frame');
    cluster.logger.whitelist('info', 'expected error while forwarding');
    cluster.logger.whitelist('info', 'OutResponse.send() after inreq timed out');
    cluster.logger.whitelist('warn', 'forwarding error frame');
    cluster.logger.whitelist('warn', 'mismatched conn.onReqDone');

    cluster.printBatches();

    // cluster.sendRequests(onResults);
    cluster.sendStreamingRequests(onResults);

    var shouldTakeHeaps = false;
    if (shouldTakeHeaps) {
        cluster.takeHeaps(20, 40, 60);
    }

    function onResults(err, results) {
        assert.ifError(err);

        // Skip bucket 0 because JIT warmup
        for (var i = 1; i < cluster.buckets.length; i++) {
            cluster.assertRange(assert, {
                index: i,
                value: results[i].errorCount,
                min: 0,
                max: 50,
                description: ' reqs with timeout of ' + cluster.buckets[i]
            });
            cluster.assertRange(assert, {
                index: i,
                value: results[i].latency.p95,
                min: 100,
                max: 140,
                description: ' p95 of requests '
            });
            cluster.assertRange(assert, {
                index: i,
                value: results[i].processMetrics.heapTotal,
                min: 50,
                max: 90,
                description: ' heap size of process '
            });
            cluster.assertRange(assert, {
                index: i,
                value: results[i].processMetrics.rss,
                min: 300,
                max: 420,
                description: ' RSS of process '
            });
        }

        assert.end();
    }
});
<|endoftext|>


<commit_before>describe('RailsResource.snapshots', function () {
    'use strict';
    var Book, $httpBackend, railsResourceFactory, railsSerializer;

    beforeEach(function () {
        module('rails')
    });

    beforeEach(inject(function (_$httpBackend_, _railsResourceFactory_, _railsSerializer_) {
        $httpBackend = _$httpBackend_;
        railsResourceFactory = _railsResourceFactory_;
        railsSerializer = _railsSerializer_;
        Book = railsResourceFactory({
            url: '/books',
            name: 'book',
            extensions: ['snapshots']
        });
    }));

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should store all keys', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        expect(book.snapshot()).toBe(0);

        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
        expect(book.$snapshots[0].$snapshots).toBeUndefined();
        expect(book).toEqualData(data);
        expect(book.$snapshots[0].$key).toBe('1234');
        expect(book.$snapshots[0]).toEqualData(data);
    });

    it('should store deep copy', function () {
        var book, data = {
            id: 1,
            $key: '1234',
            name: 'The Winds of Winter',
            author: {
                id: 1,
                name: 'George R. R. Martin'
            }
        };

        book = new Book(data);
        book.snapshot();

        expect(book.$snapshots[0].author).toBeDefined();
        expect(book.$snapshots[0].author.id).toBe(1);
        expect(book.$snapshots[0]).toEqualData(data);
    });

    it('should store multiple snapshots', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        expect(book.snapshot()).toBe(0);
        book.$key = '1235';
        expect(book.snapshot()).toBe(1);
        book.$key = '1236';
        expect(book.snapshot()).toBe(2);

        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(3);
        expect(book.$snapshots[0].$key).toBe('1234');
        expect(book.$snapshots[1].$key).toBe('1235');
        expect(book.$snapshots[2].$key).toBe('1236');
    });

    it('should rollback single version', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.rollback();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
    });

    it('should rollback deep copy', function () {
        var book, data = {
            id: 1,
            $key: '1234',
            name: 'The Winds of Winter',
            author: {
                id: 1,
                name: 'George R. R. Martin'
            }
        };

        book = new Book(data);
        book.snapshot();
        book.author = {id: 2, name: 'Hugh Howey'};
        book.rollback();

        expect(book.author).toBeDefined();
        expect(book).toEqualData(data);

        book.snapshot();
        book.author.name = 'Hugh Howey';
        book.rollback();

        expect(book.author).toBeDefined();
        expect(book).toEqualData(data);
    });

    it('should not modify source nested object on rollback', function () {
        var book, hughHoweyAuthor = {id: 2, name: 'Hugh Howey'},
            data = {
            id: 1,
            $key: '1234',
            name: 'The Winds of Winter',
            author: {
                id: 1,
                name: 'George R. R. Martin'
            }
        };

        book = new Book(data);
        book.snapshot();
        book.author = hughHoweyAuthor;
        book.rollback();

        expect(hughHoweyAuthor).toEqualData({id: 2, name: 'Hugh Howey'});
    });

    it('should allow multiple rollbacks', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.rollback();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
        book.rollback();

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should rollback specified number of versions', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.$key = '1237';
        book.rollback(2);

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
    });

    it('should not change resource on rollback if no snapshots saved', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.$key = '1235';
        book.rollback();

        expect(book.$key).toBe('1235');
    });

    it('should roll back to the first snapshot for -1', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollback(-1);

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should roll back to the first snapshot when versions exceeds available snapshots', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollback(1000);

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should roll back to version in middle', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollbackTo(1);

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
    });

    it('should roll back to first version', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollbackTo(0);

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should roll back to last version when version exceeds available versions', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.$key = '1237';
        book.rollbackTo(100);

        expect(book.$key).toBe('1236');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(2);
    });

    it('should reset snapshots on create', function () {
        var book, data = {$key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';

        $httpBackend.expectPOST('/books').respond(200, {book: {id: 1}});
        book.save();
        $httpBackend.flush();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should be able to save after rollback', function () {
        var book, data = {$key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.rollback();

        $httpBackend.expectPOST('/books').respond(200, {book: {id: 1}});
        book.save();
        $httpBackend.flush();

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should reset snapshots on update', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';

        $httpBackend.expectPUT('/books/1').respond(200, {book: {id: 1}});
        book.save();
        $httpBackend.flush();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should reset snapshots on delete', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';

        $httpBackend.expectDELETE('/books/1').respond(200, {book: {id: 1}});
        book.delete();
        $httpBackend.flush();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should call rollback callback on rollback', function () {
        var book, callbackCalled = false, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot(function () {
            callbackCalled = true;
        });
        book.rollback();
        expect(callbackCalled).toBe(true);
    });

    it('should call correct rollback callback on each rollback', function () {
        var book, firstCallbackCalled = false, secondCallbackCalled = false,
            data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot(function () {
            firstCallbackCalled = true;
        });
        book.$key = '1235';
        book.snapshot(function () {
            secondCallbackCalled = true;
        });
        book.$key = '1236';

        book.rollback();
        expect(book.$key).toBe('1235');
        expect(firstCallbackCalled).toBe(false);
        expect(secondCallbackCalled).toBe(true);

        book.rollback();
        expect(book.$key).toBe('1234');
        expect(firstCallbackCalled).toBe(true);
        expect(secondCallbackCalled).toBe(true);
    });

    it('should detect unsnapped changes', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        expect(book.unsnappedChanges()).toBe(true);

        book.snapshot();
        expect(book.unsnappedChanges()).toBe(false);

        book.name = 'Harry Potter';
        expect(book.unsnappedChanges()).toBe(true);

        book.snapshot();
        expect(book.unsnappedChanges()).toBe(false);

        // angular.equals ignores $-prefixed properties
        book.$key = '1235'
        expect(book.unsnappedChanges()).toBe(false);
    });

    describe('serializer', function () {
        beforeEach(function () {
            Book.configure({
                serializer: railsSerializer(function () {
                    this.exclude('author');
                })
            });
        });

        it('should exclude author from snapshot and rollback', function () {
            var book, data = {
                id: 1,
                $key: '1234',
                name: 'The Winds of Winter',
                author: {
                    id: 1,
                    name: 'George R. R. Martin'
                }
            };

            book = new Book(data);
            book.snapshot();
            book.author.name = 'George Orwell';

            expect(book.$snapshots[0].author).not.toBeDefined();
            expect(book.author).toEqualData({id: 1, name: 'George Orwell'});

            book.rollback();
            // should still be George Orwell since it wasn't snapshotted
            expect(book.author).toEqualData({id: 1, name: 'George Orwell'});
        });

    });

    describe('snapshotSerializer', function () {
        beforeEach(function () {
            Book.configure({
                serializer: railsSerializer(function () {
                    this.exclude('author');
                }),
                snapshotSerializer: railsSerializer(function () {
                    this.exclude('$key');
                })
            });
        });

        it('should include author and exclude $key from snapshot and rollback', function () {
            var book, data = {
                id: 1,
                $key: '1234',
                name: 'The Winds of Winter',
                author: {
                    id: 1,
                    name: 'George R. R. Martin'
                }
            };

            book = new Book(data);
            book.snapshot();
            book.$key = '1235';
            book.author.name = 'George Orwell';

            expect(book.$snapshots[0].author).toBeDefined();
            expect(book.$snapshots[0].$key).not.toBeDefined();
            expect(book.$key).toBe('1235');
            expect(book.author).toEqualData({id: 1, name: 'George Orwell'});

            book.rollback();
            // should be 1235 since it wasn't snapshotted
            expect(book.$key).toBe('1235');
            // should be George R. R. Martin since it was snapshotted
            expect(book.author).toEqualData({id: 1, name: 'George R. R. Martin'});
        });

    });
});<commit_msg>Added camelCase spec<commit_after>describe('RailsResource.snapshots', function () {
    'use strict';
    var Book, $httpBackend, railsResourceFactory, railsSerializer;

    beforeEach(function () {
        module('rails')
    });

    beforeEach(inject(function (_$httpBackend_, _railsResourceFactory_, _railsSerializer_) {
        $httpBackend = _$httpBackend_;
        railsResourceFactory = _railsResourceFactory_;
        railsSerializer = _railsSerializer_;
        Book = railsResourceFactory({
            url: '/books',
            name: 'book',
            extensions: ['snapshots']
        });
    }));

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should store all keys', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        expect(book.snapshot()).toBe(0);

        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
        expect(book.$snapshots[0].$snapshots).toBeUndefined();
        expect(book).toEqualData(data);
        expect(book.$snapshots[0].$key).toBe('1234');
        expect(book.$snapshots[0]).toEqualData(data);
    });

    it('should store deep copy', function () {
        var book, data = {
            id: 1,
            $key: '1234',
            name: 'The Winds of Winter',
            author: {
                id: 1,
                name: 'George R. R. Martin'
            }
        };

        book = new Book(data);
        book.snapshot();

        expect(book.$snapshots[0].author).toBeDefined();
        expect(book.$snapshots[0].author.id).toBe(1);
        expect(book.$snapshots[0]).toEqualData(data);
    });

    it('should store multiple snapshots', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        expect(book.snapshot()).toBe(0);
        book.$key = '1235';
        expect(book.snapshot()).toBe(1);
        book.$key = '1236';
        expect(book.snapshot()).toBe(2);

        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(3);
        expect(book.$snapshots[0].$key).toBe('1234');
        expect(book.$snapshots[1].$key).toBe('1235');
        expect(book.$snapshots[2].$key).toBe('1236');
    });

    it('should rollback single version', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.rollback();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
    });

    it('should rollback deep copy', function () {
        var book, data = {
            id: 1,
            $key: '1234',
            name: 'The Winds of Winter',
            author: {
                id: 1,
                name: 'George R. R. Martin'
            }
        };

        book = new Book(data);
        book.snapshot();
        book.author = {id: 2, name: 'Hugh Howey'};
        book.rollback();

        expect(book.author).toBeDefined();
        expect(book).toEqualData(data);

        book.snapshot();
        book.author.name = 'Hugh Howey';
        book.rollback();

        expect(book.author).toBeDefined();
        expect(book).toEqualData(data);
    });

    it('should not modify source nested object on rollback', function () {
        var book, hughHoweyAuthor = {id: 2, name: 'Hugh Howey'},
            data = {
            id: 1,
            $key: '1234',
            name: 'The Winds of Winter',
            author: {
                id: 1,
                name: 'George R. R. Martin'
            }
        };

        book = new Book(data);
        book.snapshot();
        book.author = hughHoweyAuthor;
        book.rollback();

        expect(hughHoweyAuthor).toEqualData({id: 2, name: 'Hugh Howey'});
    });

    it('should allow multiple rollbacks', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.rollback();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
        book.rollback();

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should rollback specified number of versions', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.$key = '1237';
        book.rollback(2);

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
    });

    it('should not change resource on rollback if no snapshots saved', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.$key = '1235';
        book.rollback();

        expect(book.$key).toBe('1235');
    });

    it('should roll back to the first snapshot for -1', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollback(-1);

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should roll back to the first snapshot when versions exceeds available snapshots', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollback(1000);

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should roll back to version in middle', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollbackTo(1);

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(1);
    });

    it('should roll back to first version', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.rollbackTo(0);

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should roll back to last version when version exceeds available versions', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.snapshot();
        book.$key = '1236';
        book.snapshot();
        book.$key = '1237';
        book.rollbackTo(100);

        expect(book.$key).toBe('1236');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(2);
    });

    it('should reset snapshots on create', function () {
        var book, data = {$key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';

        $httpBackend.expectPOST('/books').respond(200, {book: {id: 1}});
        book.save();
        $httpBackend.flush();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should be able to save after rollback', function () {
        var book, data = {$key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';
        book.rollback();

        $httpBackend.expectPOST('/books').respond(200, {book: {id: 1}});
        book.save();
        $httpBackend.flush();

        expect(book.$key).toBe('1234');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should reset snapshots on update', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';

        $httpBackend.expectPUT('/books/1').respond(200, {book: {id: 1}});
        book.save();
        $httpBackend.flush();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should reset snapshots on delete', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot();
        book.$key = '1235';

        $httpBackend.expectDELETE('/books/1').respond(200, {book: {id: 1}});
        book.delete();
        $httpBackend.flush();

        expect(book.$key).toBe('1235');
        expect(book.$snapshots).toBeDefined();
        expect(book.$snapshots.length).toBe(0);
    });

    it('should call rollback callback on rollback', function () {
        var book, callbackCalled = false, data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot(function () {
            callbackCalled = true;
        });
        book.rollback();
        expect(callbackCalled).toBe(true);
    });

    it('should call correct rollback callback on each rollback', function () {
        var book, firstCallbackCalled = false, secondCallbackCalled = false,
            data = {id: 1, $key: '1234', name: 'The Winds of Winter'};
        book = new Book(data);
        book.snapshot(function () {
            firstCallbackCalled = true;
        });
        book.$key = '1235';
        book.snapshot(function () {
            secondCallbackCalled = true;
        });
        book.$key = '1236';

        book.rollback();
        expect(book.$key).toBe('1235');
        expect(firstCallbackCalled).toBe(false);
        expect(secondCallbackCalled).toBe(true);

        book.rollback();
        expect(book.$key).toBe('1234');
        expect(firstCallbackCalled).toBe(true);
        expect(secondCallbackCalled).toBe(true);
    });

    it('should detect unsnapped changes', function () {
        var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter', theAuthor: 'George R.R. Martin'};
        book = new Book(data);
        expect(book.unsnappedChanges()).toBe(true);

        book.snapshot();
        expect(book.unsnappedChanges()).toBe(false);

        book.name = 'Harry Potter';
        expect(book.unsnappedChanges()).toBe(true);

        book.snapshot();
        expect(book.unsnappedChanges()).toBe(false);

        book.theAuthor = 'J.K. Rowling';
        expect(book.unsnappedChanges()).toBe(true);

        book.snapshot();
        expect(book.unsnappedChanges()).toBe(false);

        // angular.equals ignores $-prefixed properties
        book.$key = '1235'
        expect(book.unsnappedChanges()).toBe(false);
    });

    describe('serializer', function () {
        beforeEach(function () {
            Book.configure({
                serializer: railsSerializer(function () {
                    this.exclude('author');
                })
            });
        });

        it('should exclude author from snapshot and rollback', function () {
            var book, data = {
                id: 1,
                $key: '1234',
                name: 'The Winds of Winter',
                author: {
                    id: 1,
                    name: 'George R. R. Martin'
                }
            };

            book = new Book(data);
            book.snapshot();
            book.author.name = 'George Orwell';

            expect(book.$snapshots[0].author).not.toBeDefined();
            expect(book.author).toEqualData({id: 1, name: 'George Orwell'});

            book.rollback();
            // should still be George Orwell since it wasn't snapshotted
            expect(book.author).toEqualData({id: 1, name: 'George Orwell'});
        });

    });

    describe('snapshotSerializer', function () {
        beforeEach(function () {
            Book.configure({
                serializer: railsSerializer(function () {
                    this.exclude('author');
                }),
                snapshotSerializer: railsSerializer(function () {
                    this.exclude('$key');
                })
            });
        });

        it('should include author and exclude $key from snapshot and rollback', function () {
            var book, data = {
                id: 1,
                $key: '1234',
                name: 'The Winds of Winter',
                author: {
                    id: 1,
                    name: 'George R. R. Martin'
                }
            };

            book = new Book(data);
            book.snapshot();
            book.$key = '1235';
            book.author.name = 'George Orwell';

            expect(book.$snapshots[0].author).toBeDefined();
            expect(book.$snapshots[0].$key).not.toBeDefined();
            expect(book.$key).toBe('1235');
            expect(book.author).toEqualData({id: 1, name: 'George Orwell'});

            book.rollback();
            // should be 1235 since it wasn't snapshotted
            expect(book.$key).toBe('1235');
            // should be George R. R. Martin since it was snapshotted
            expect(book.author).toEqualData({id: 1, name: 'George R. R. Martin'});
        });

    });
});<|endoftext|>


<commit_before>/*
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 *
 * Developed by: Federico M. Facca - Martel Innovate
 */

/* eslint-disable consistent-return */
/* eslint-disable no-self-assign */
/* eslint-disable no-unused-vars */

const jexl = require('jexl');
const errors = require('../errors');
const logger = require('logops');
const config = require('../commonConfig');
const logContext = {
    op: 'IoTAgentNGSI.JEXL'
};

jexl.addTransform('indexOf', (val, char) => String(val).indexOf(char));
jexl.addTransform('length', (val) => String(val).length);
jexl.addTransform('trim', (val) => String(val).trim());
jexl.addTransform('substr', (val, int1, int2) => String(val).substr(int1, int2));

function parse(expression, context, callback) {
    let result;
    let error;

    try {
        result = jexl.evalSync(expression, context);
        logger.debug(logContext, 'parse expression "[%j]" over "[%j]" result "[%j]" ', expression, context, result);
    } catch (e) {
        error = new errors.InvalidExpression(expression);
        if (callback) {
            callback(error);
        } else {
            throw error;
        }
    }

    if (callback) {
        callback(null, result);
    } else {
        return result;
    }
}

function extractContext(attributeList) {
    const context = {};
    let value;

    for (let i = 0; i < attributeList.length; i++) {
        if (
            !Number.isNaN(Number.parseFloat(attributeList[i].value)) &&
            !Number.isInteger(Number.parseFloat(attributeList[i].value))
        ) {
            value = Number.parseFloat(attributeList[i].value);
        } else if (!Number.isNaN(Number.parseInt(attributeList[i].value))) {
            value = Number.parseInt(attributeList[i].value);
        } else if (String(attributeList[i].value) === 'true') {
            value = true;
        } else if (String(attributeList[i].value) === 'false') {
            value = false;
        } else {
            value = attributeList[i].value;
        }
        if (attributeList[i].name) {
            context[attributeList[i].name] = value;
        }
        /*jshint camelcase: false */
        if (attributeList[i].object_id) {
            context[attributeList[i].object_id] = value;
        }
        /*jshint camelcase: true */
    }

    return context;
}

function applyExpression(expression, context, typeInformation) {
    const result = jexl.evalSync(expression, context);
    logger.debug(logContext, 'applyExpression "[%j]" over "[%j]" result "[%j]" ', expression, context, result);
    let expressionResult = result !== undefined ? result : expression;
    return expressionResult;
}

function expressionApplier(context, typeInformation) {
    return function (attribute) {
        /**
         * Determines if a value is of type float
         *
         * @param      {String}   value       Value to be analyzed
         * @return     {boolean}              True if float, False otherwise.
         */
        function isFloat(value) {
            return !isNaN(value) && value.toString().indexOf('.') !== -1;
        }

        const newAttribute = {
            name: attribute.name,
            type: attribute.type
        };

        /*jshint camelcase: false */
        if (config.isCurrentNgsi() && attribute.object_id) {
            newAttribute.object_id = attribute.object_id;
        }

        newAttribute.value = applyExpression(attribute.expression, context, typeInformation);
        return newAttribute;
    };
}

function isTransform(identifier) {
    return jexl.getTransform(identifier) !== (null || undefined);
}

function contextAvailable(expression, context) {
    let error;
    try {
        const lexer = jexl._getLexer();
        const identifiers = lexer.tokenize(expression).filter(function (token) {
            return token.type === 'identifier';
        });
        const keys = Object.keys(context);
        let validContext = true;
        identifiers.some(function (element) {
            if (!keys.includes(element.value) && !isTransform(element.value)) {
                validContext = false;
                logger.warn(
                    logContext,
                    'For expression "[%s]" context "[%j]" does not have element %s',
                    expression,
                    context,
                    element.value
                );
            }
            // FIXME: Workaround to allow keys of JSON geopoints
            if (element.value === 'type' || element.value === 'coordinates') {
                validContext = true;
            }
            return validContext === false;
        });
        if (validContext) {
            jexl.evalSync(expression, context);
        }
        return validContext;
    } catch (e) {
        error = new errors.InvalidExpression(expression);
        throw error;
    }
}

function processExpressionAttributes(typeInformation, list, context) {
    return list
        .filter(function (item) {
            return item.expression && contextAvailable(item.expression, context);
        })
        .map(expressionApplier(context, typeInformation));
}

exports.extractContext = extractContext;
exports.processExpressionAttributes = processExpressionAttributes;
exports.contextAvailable = contextAvailable;
exports.applyExpression = applyExpression;
exports.parse = parse;
<commit_msg>simplify contextAvailable for jexl parser<commit_after>/*
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of fiware-iotagent-lib
 *
 * fiware-iotagent-lib is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * fiware-iotagent-lib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with fiware-iotagent-lib.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::daniel.moranjimenez@telefonica.com
 *
 * Developed by: Federico M. Facca - Martel Innovate
 */

/* eslint-disable consistent-return */
/* eslint-disable no-self-assign */
/* eslint-disable no-unused-vars */

const jexl = require('jexl');
const errors = require('../errors');
const logger = require('logops');
const config = require('../commonConfig');
const logContext = {
    op: 'IoTAgentNGSI.JEXL'
};

jexl.addTransform('indexOf', (val, char) => String(val).indexOf(char));
jexl.addTransform('length', (val) => String(val).length);
jexl.addTransform('trim', (val) => String(val).trim());
jexl.addTransform('substr', (val, int1, int2) => String(val).substr(int1, int2));

function parse(expression, context, callback) {
    let result;
    let error;

    try {
        result = jexl.evalSync(expression, context);
        logger.debug(logContext, 'parse expression "[%j]" over "[%j]" result "[%j]" ', expression, context, result);
    } catch (e) {
        error = new errors.InvalidExpression(expression);
        if (callback) {
            callback(error);
        } else {
            throw error;
        }
    }

    if (callback) {
        callback(null, result);
    } else {
        return result;
    }
}

function extractContext(attributeList) {
    const context = {};
    let value;

    for (let i = 0; i < attributeList.length; i++) {
        if (
            !Number.isNaN(Number.parseFloat(attributeList[i].value)) &&
            !Number.isInteger(Number.parseFloat(attributeList[i].value))
        ) {
            value = Number.parseFloat(attributeList[i].value);
        } else if (!Number.isNaN(Number.parseInt(attributeList[i].value))) {
            value = Number.parseInt(attributeList[i].value);
        } else if (String(attributeList[i].value) === 'true') {
            value = true;
        } else if (String(attributeList[i].value) === 'false') {
            value = false;
        } else {
            value = attributeList[i].value;
        }
        if (attributeList[i].name) {
            context[attributeList[i].name] = value;
        }
        /*jshint camelcase: false */
        if (attributeList[i].object_id) {
            context[attributeList[i].object_id] = value;
        }
        /*jshint camelcase: true */
    }

    return context;
}

function applyExpression(expression, context, typeInformation) {
    const result = jexl.evalSync(expression, context);
    logger.debug(logContext, 'applyExpression "[%j]" over "[%j]" result "[%j]" ', expression, context, result);
    let expressionResult = result !== undefined ? result : expression;
    return expressionResult;
}

function expressionApplier(context, typeInformation) {
    return function (attribute) {
        /**
         * Determines if a value is of type float
         *
         * @param      {String}   value       Value to be analyzed
         * @return     {boolean}              True if float, False otherwise.
         */
        function isFloat(value) {
            return !isNaN(value) && value.toString().indexOf('.') !== -1;
        }

        const newAttribute = {
            name: attribute.name,
            type: attribute.type
        };

        /*jshint camelcase: false */
        if (config.isCurrentNgsi() && attribute.object_id) {
            newAttribute.object_id = attribute.object_id;
        }

        newAttribute.value = applyExpression(attribute.expression, context, typeInformation);
        return newAttribute;
    };
}

function isTransform(identifier) {
    return jexl.getTransform(identifier) !== (null || undefined);
}

function contextAvailable(expression, context) {
    let error;
    try {
        let validContext = true;
        jexl.evalSync(expression, context);
        return validContext;
    } catch (e) {
        error = new errors.InvalidExpression(expression);
        throw error;
    }
}

function processExpressionAttributes(typeInformation, list, context) {
    return list
        .filter(function (item) {
            return item.expression && contextAvailable(item.expression, context);
        })
        .map(expressionApplier(context, typeInformation));
}

exports.extractContext = extractContext;
exports.processExpressionAttributes = processExpressionAttributes;
exports.contextAvailable = contextAvailable;
exports.applyExpression = applyExpression;
exports.parse = parse;
<|endoftext|>


<commit_before>var Reaction = require("../reaction")
  , get = require("../util").get
  , rules = require("../rules")
  , ModelReaction = require("./model")

var VariableReaction = Reaction.extend({

  setFrom: function(key) {
    var newVal = this.get(key)
      , oldVal
      , shouldTriggerChange = false

    if(this.isInput) {
      oldVal = this.el.val()
      if(this.el.attr("type") === "checkbox") {
        if($(this.el).prop('checked') !== !!newVal) {
          shouldTriggerChange = true
        }
        $(this.el).prop("checked", !!newVal)
      } else if(this.el.attr("type") === "radio") {
        if(oldVal == newVal) {
          if (!$(this.el).prop('checked')) {
            shouldTriggerChange = true
          }
          $(this.el).prop("checked", true)
        } else {
          if ($(this.el).prop('checked')) {
            shouldTriggerChange = true
          }
          $(this.el).prop("checked", false)
        }
      } else if(newVal !== oldVal) {
        shouldTriggerChange = true
        //ugly nesting, but have to check for undefined because
        //this gets called by many things and newVal isn't always defined
        if (typeof newVal !== 'undefined') {
          $(this.el).val(newVal.toString())
        }
          else{
          $(this.el).val(newVal)
        }
      }
      if (shouldTriggerChange) {
        this.triggerDOMChange()
      }
    } else {
      oldVal = $(this.el).html()
      if(oldVal !== newVal) {
        $(this.el).html(newVal)
      }
    }
  },

  triggerDOMChange: function () {
      $(this.el).trigger('change')
  },

  init: function(next) {
    this.setFrom(this.variableName)
    next()
  },

  observe: function() {
    var key = this.variableName
      , that = this
      , model = that.model
      , events = "input change"

    if((this.isInput || this.isContentEditable) && !this.isReadOnly) {
      this.clearUiEvent(events)
      this.uiEvent(events, function() {
        if(that.isContentEditable) {
          return model.set(key, that.el.html(), { validate: true })
        }
        if(that.el.attr("type") === "checkbox" && !that.el.prop("checked")) {
          return model.set(key, false, { validate: true })
        }
        if(that.el.attr("type") === "radio") {
          if(that.el.prop('checked')) {
            return model.set(key, that.el.val(), {validate: true})
          } else {
            return
          }
        }
        model.set(key, that.el.val(), { validate: true })
      })
    }

    this.change(key, function() {
      this.setFrom(key)
    }, this)
  }
}, {
  selector: "[class]",

  reactIf: function(el) {
    return rules.variable(el)
  },

  parse: function(el) {
    return {
      isReadOnly: el.is("[data-readonly]"),
      isInput: el.is(":input:not(button)"),
      isContentEditable: el.is("[contenteditable]"),
      variableName: rules.variable(el)
    }
  }
})

module.exports = VariableReaction
<commit_msg>only do the jquerification of the el once<commit_after>var Reaction = require("../reaction")
  , get = require("../util").get
  , rules = require("../rules")
  , ModelReaction = require("./model")

var VariableReaction = Reaction.extend({

  setFrom: function(key) {
    var newVal = this.get(key)
      , oldVal
      , shouldTriggerChange = false
      , el = $(this.el)

    if(this.isInput) {
      oldVal = el.val()
      if(el.attr("type") === "checkbox") {
        if(el.prop('checked') !== !!newVal) {
          shouldTriggerChange = true
        }
        el.prop("checked", !!newVal)
      } else if(el.attr("type") === "radio") {
        if(oldVal == newVal) {
          if (!el.prop('checked')) {
            shouldTriggerChange = true
          }
          el.prop("checked", true)
        } else {
          if (el.prop('checked')) {
            shouldTriggerChange = true
          }
          el.prop("checked", false)
        }
      } else if(newVal !== oldVal) {
        shouldTriggerChange = true
        //ugly nesting, but have to check for undefined because
        //this gets called by many things and newVal isn't always defined
        if (typeof newVal !== 'undefined') {
          el.val(newVal.toString())
        }
          else{
          el.val(newVal)
        }
      }
      if (shouldTriggerChange) {
        this.triggerDOMChange()
      }
    } else {
      oldVal = el.html()
      if(oldVal !== newVal) {
        el.html(newVal)
      }
    }
  },

  triggerDOMChange: function () {
      $(this.el).trigger('change')
  },

  init: function(next) {
    this.setFrom(this.variableName)
    next()
  },

  observe: function() {
    var key = this.variableName
      , that = this
      , model = that.model
      , events = "input change"

    if((this.isInput || this.isContentEditable) && !this.isReadOnly) {
      this.clearUiEvent(events)
      this.uiEvent(events, function() {
        if(that.isContentEditable) {
          return model.set(key, that.el.html(), { validate: true })
        }
        if(that.el.attr("type") === "checkbox" && !that.el.prop("checked")) {
          return model.set(key, false, { validate: true })
        }
        if(that.el.attr("type") === "radio") {
          if(that.el.prop('checked')) {
            return model.set(key, that.el.val(), {validate: true})
          } else {
            return
          }
        }
        model.set(key, that.el.val(), { validate: true })
      })
    }

    this.change(key, function() {
      this.setFrom(key)
    }, this)
  }
}, {
  selector: "[class]",

  reactIf: function(el) {
    return rules.variable(el)
  },

  parse: function(el) {
    return {
      isReadOnly: el.is("[data-readonly]"),
      isInput: el.is(":input:not(button)"),
      isContentEditable: el.is("[contenteditable]"),
      variableName: rules.variable(el)
    }
  }
})

module.exports = VariableReaction
<|endoftext|>