<commit_before>"use strict";

import ReactDOM from "react-dom";
import JSX from "react-jsx";

(() => {
	const component$ = {};

	const reactVendorDirective = function reactVendorDrective(
		$rootScope
	) {
		return {
			link: (scope, element) => {
				const watch = $rootScope.$watch;

				watch("component", (nv, ov) => {
					ReactDOM.render(
						(JSX.client(nv.component, {}))(nv.vm),
						element[0]
					);
				});
			}
		};
	};

	const reactVendorService = function reactVendorService(
		$rootScope,
		$templateCache
	) {
		component$.view = (component, vm) => {
			$rootScope.component = {
				component: $templateCache.get(component).join(""),
				vm
			};
		};

		return component$;
	};

	angular
		.module("react.vendor.directive", ["react.vendor.service"])
		.directive("component", reactVendorDirective);
	;

	angular
		.module("react.vendor.service", [])
		.factory("component$", reactVendorService)
	;
})();
<commit_msg>Edits<commit_after>"use strict";

import ReactDOM from "react-dom";
import JSX from "react-jsx";

(() => {
	const component$ = {};

	const reactVendorDirective = function reactVendorDrective(
		$rootScope
	) {
		return {
			link: (scope, element) => {
				const watch = $rootScope.$watch;

				watch("component", (nv, ov) => {
					ReactDOM.render(
						(JSX.client(nv.component, {}))(nv.vm),
						element[0]
					);
				});
			}
		};
	};

	const reactVendorService = function reactVendorService(
		$rootScope,
		$templateCache
	) {
		component$.view = (component, vm) => {
			$rootScope.component = {
				component: $templateCache.get(component).join(""),
				vm
			};
		};

		return component$;
	};

	angular
		.module("react.vendor.directive", [])
		.directive("component", reactVendorDirective);
	;

	angular
		.module("react.vendor.service", [])
		.factory("component$", reactVendorService)
	;
})();
<|endoftext|>


<commit_before>// __________________________________
//  Site Configuration              |
// ----------------------------------
//        \   ^__^
//         \  (oo)\_______
//            (__)\       )\/\
//                ||----w |
//                ||     ||
//
//  Pretty self-explanatory, except for these:
//
//  qolembedURL     if you have a qol embed install, put the location here, otherwise set to null
//  qolreportURL    if you have a qol report install, put the location here, otherwise set to null
//  qoldashboardURL     if you have a qol dashboard install, put the location here, otherwise set to null
//  contactForm     location of your contact form if you have one for the dashboard, otherwise null
// POST arguments to the contact page will be:
//     email : sender email,
//     url: the current window location,
//     agent: users's browser info,
//     subject: "Whatever",
//     to: email address(s) to send the feedback to,
//     message: "I hate your website or whatever"
//  whatsnew        an array of recently updated metric id's to put in a what's new box, like ["2", "12"].
//                  set to null if you've got none
//  contacts "tobin.bradley@gmail.com,qualityoflife@charlottenc.gov",
//

let siteConfig = {
  neighborhoodDescriptor: 'NPA',
  neighborhoodDefinition:
    'Neighborhood Profile Areas (NPAs) are geographic areas used for the organization and presentation of data in the Quality of Life Study. The boundaries were developed with community input and are based on one or more Census block groups.',
  gaKey: 'UA-48797957-1',
  keywords:
    'GIS,Mecklenburg County,parks,libraries,schools,environment,impervious surface,floodplain,zoning,assessment,tax,photos,government',
  author: 'Tobin Bradley',
  title: 'Quality of Life Explorer',
  jurisdiction: 'Charlotte/Mecklenburg',
  description:
    'Exploring neighborhood character, economics, education, engagement, environment, health, housing, safety and transportation.',
  qolembedURL: 'https://mcmap.org/qol-embed/',
  qolreportURL: 'https://mcmap.org/qol-report/',
  qoldashboardURL: 'https://mcmap.org/qol/',
  contactForm: 'https://mcmap.org/utilities/feedback.php',
  contacts: 'tobin.bradley@gmail.com,qualityoflife@charlottenc.gov',
  whatsnew: ['2', '12'],
  links: [
    {
      href: 'http://charlottenc.gov/HNS/CE/CommunityInfo/Pages/QOL.aspx',
      text: 'About',
    },
    {
      href: 'downloads/qol-data.zip',
      text: 'Download Data',
    },
    {
      href: 'http://maps.co.mecklenburg.nc.us/openmapping/',
      text: 'Mecklenburg County Open Mapping',
    },
    {
      href: 'http://clt.charlotte.opendata.arcgis.com/',
      text: 'City of Charlotte Open Data Portal',
    },
  ],
};

module.exports = siteConfig;
<commit_msg>update what's new<commit_after>// __________________________________
//  Site Configuration              |
// ----------------------------------
//        \   ^__^
//         \  (oo)\_______
//            (__)\       )\/\
//                ||----w |
//                ||     ||
//
//  Pretty self-explanatory, except for these:
//
//  qolembedURL     if you have a qol embed install, put the location here, otherwise set to null
//  qolreportURL    if you have a qol report install, put the location here, otherwise set to null
//  qoldashboardURL     if you have a qol dashboard install, put the location here, otherwise set to null
//  contactForm     location of your contact form if you have one for the dashboard, otherwise null
// POST arguments to the contact page will be:
//     email : sender email,
//     url: the current window location,
//     agent: users's browser info,
//     subject: "Whatever",
//     to: email address(s) to send the feedback to,
//     message: "I hate your website or whatever"
//  whatsnew        an array of recently updated metric id's to put in a what's new box, like ["2", "12"].
//                  set to null if you've got none
//  contacts "tobin.bradley@gmail.com,qualityoflife@charlottenc.gov",
//

let siteConfig = {
  neighborhoodDescriptor: 'NPA',
  neighborhoodDefinition:
    'Neighborhood Profile Areas (NPAs) are geographic areas used for the organization and presentation of data in the Quality of Life Study. The boundaries were developed with community input and are based on one or more Census block groups.',
  gaKey: 'UA-48797957-1',
  keywords:
    'GIS,Mecklenburg County,parks,libraries,schools,environment,impervious surface,floodplain,zoning,assessment,tax,photos,government',
  author: 'Tobin Bradley',
  title: 'Quality of Life Explorer',
  jurisdiction: 'Charlotte/Mecklenburg',
  description:
    'Exploring neighborhood character, economics, education, engagement, environment, health, housing, safety and transportation.',
  qolembedURL: 'https://mcmap.org/qol-embed/',
  qolreportURL: 'https://mcmap.org/qol-report/',
  qoldashboardURL: 'https://mcmap.org/qol/',
  contactForm: 'https://mcmap.org/utilities/feedback.php',
  contacts: 'tobin.bradley@gmail.com,qualityoflife@charlottenc.gov',
  whatsnew: [
    '67',
    '71',
    '82',
    '7',
    '6',
    '42',
    '53',
    '83',
    '30',
    '5',
    '73',
    '9',
    '8',
    '19',
    '41',
    '11',
    '4',
    '35',
    '64',
    '63'
  ],
  links: [
    {
      href: 'http://charlottenc.gov/HNS/CE/CommunityInfo/Pages/QOL.aspx',
      text: 'About'
    },
    {
      href: 'downloads/qol-data.zip',
      text: 'Download Data'
    },
    {
      href: 'http://maps.co.mecklenburg.nc.us/openmapping/',
      text: 'Mecklenburg County Open Mapping'
    },
    {
      href: 'http://clt.charlotte.opendata.arcgis.com/',
      text: 'City of Charlotte Open Data Portal'
    }
  ]
};

module.exports = siteConfig;
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Component.extend({
  store: Ember.inject.service(),

  user: null,
  users: [],
  provider: null,
  client: null,
  link: null,
  isAdmin: false,
  isProvider: false,
  isClient: false,

  didReceiveAttrs() {
    this._super(...arguments);

    this.set('provider', this.get('model.provider'));
    this.set('client', this.get('model.client'));

    if (this.get('currentUser').get('isAdmin')) {
      this.set('isAdmin', true);
    } else if (this.get('currentUser').get('isProvider')) {
      this.set('isProvider', true);
    } else if (this.get('currentUser').get('isClient')) {
      this.set('isClient', true);
    }

    this.searchUser(null);
    this.searchRole();
  },

  searchUser(query) {
    this.set('users', this.get('store').query('user', { query: query, registry: true, 'page[size]': 25 }));
  },
  selectUser(user) {
    let self = this;
    this.get('store').findRecord('user', user.id, { reload: true, registry: true, include: 'role,client,provider,sandbox' }).then(function(user) {
      self.set('user', user);
      self.selectRole(self.get('user').get('role'));
      if (user.get('provider')) {
        self.selectProvider(user.get('provider'));
      }
      if (user.get('client')) {
        self.selectClient(user.get('client'))
      }
    });
  },
  searchRole() {
    if (this.get('client')) {
      this.set('roles', this.get('store').query('role', { scope: 'client' }));
    } else if (this.get('provider')) {
      this.set('roles', this.get('store').query('role', { scope: 'provider' }));
    } else {
      this.set('roles', this.get('store').findAll('role'));
    }
  },
  selectRole(role) {
    this.set('role', role);
    this.get('user').set('role', role);
  },
  selectProvider(provider) {
    this.set('provider', provider)
    this.get('user').set('provider', provider);

    if (provider) {
      this.set('clients', this.get('store').query('client', { sort: 'name', 'provider-id': this.get('provider').get('id'), 'page[size]': 10 }));
      this.selectClient(this.get('user').get('client'));
    } else {
      this.set('clients', []);
      this.selectClient(null);
    }
  },
  searchClient(query) {
    this.set('clients', this.get('store').query('client', { 'query': query, sort: 'name', 'provider-id': this.get('provider').get('id'), 'page[size]': 10 }));
  },
  selectClient(client) {
    if (client) {
      this.set('client', client)
      if (client.get('isSandbox')) {
        this.get('user').set('sandbox-id', client.id);
      } else {
        this.get('user').set('client', client);
      }
    }
  },

  actions: {
    selectUser(user) {
      this.selectUser(user);
    },
    searchUser(query) {
      this.searchUser(query);
    },
    searchRole() {
      this.searchRole();
    },
    selectRole(role) {
      this.selectRole(role);
    },
    searchProvider(query) {
      this.set('providers', this.get('store').query('provider', { 'query': query, sort: 'name', 'page[size]': 10 }));
    },
    selectProvider(provider) {
      this.selectProvider(provider);
    },
    searchClient(query) {
      this.searchClient(query);
    },
    selectClient(client) {
      this.selectClient(client);
    },
    submit() {
      let self = this;
      if (this.get('client')) {
        this.get('user').set('client', this.get('client'));
        this.get('user').save().then(function(user) {
          self.get('router').transitionTo('clients.show.users', user.get('client'));
        });
      } else if (this.get('provider')) {
        this.get('user').set('provider', this.get('provider'));
        this.get('user').save().then(function(user) {
          self.get('router').transitionTo('providers.show.users', user.get('provider'));
        });
      } else {
        this.get('user').save().then(function(user) {
          self.get('router').transitionTo('users');
        });
      }
    },
    cancel() {
      if (this.get('client')) {
        this.get('router').transitionTo('clients.show.users', this.get('client'));
      } else if (this.get('provider')) {
        this.get('router').transitionTo('providers.show.users', this.get('provider'));
      } else {
        this.get('router').transitionTo('users');
      }
    }
  }
});
<commit_msg>fixed eslint error<commit_after>import Ember from 'ember';

export default Ember.Component.extend({
  store: Ember.inject.service(),

  user: null,
  users: [],
  provider: null,
  client: null,
  link: null,
  isAdmin: false,
  isProvider: false,
  isClient: false,

  didReceiveAttrs() {
    this._super(...arguments);

    this.set('provider', this.get('model.provider'));
    this.set('client', this.get('model.client'));

    if (this.get('currentUser').get('isAdmin')) {
      this.set('isAdmin', true);
    } else if (this.get('currentUser').get('isProvider')) {
      this.set('isProvider', true);
    } else if (this.get('currentUser').get('isClient')) {
      this.set('isClient', true);
    }

    this.searchUser(null);
    this.searchRole();
  },

  searchUser(query) {
    this.set('users', this.get('store').query('user', { query: query, registry: true, 'page[size]': 25 }));
  },
  selectUser(user) {
    let self = this;
    this.get('store').findRecord('user', user.id, { reload: true, registry: true, include: 'role,client,provider,sandbox' }).then(function(user) {
      self.set('user', user);
      self.selectRole(self.get('user').get('role'));
      if (user.get('provider')) {
        self.selectProvider(user.get('provider'));
      }
      if (user.get('client')) {
        self.selectClient(user.get('client'))
      }
    });
  },
  searchRole() {
    if (this.get('client')) {
      this.set('roles', this.get('store').query('role', { scope: 'client' }));
    } else if (this.get('provider')) {
      this.set('roles', this.get('store').query('role', { scope: 'provider' }));
    } else {
      this.set('roles', this.get('store').findAll('role'));
    }
  },
  selectRole(role) {
    this.set('role', role);
    this.get('user').set('role', role);
  },
  selectProvider(provider) {
    this.set('provider', provider)
    this.get('user').set('provider', provider);

    if (provider) {
      this.set('clients', this.get('store').query('client', { sort: 'name', 'provider-id': this.get('provider').get('id'), 'page[size]': 10 }));
      this.selectClient(this.get('user').get('client'));
    } else {
      this.set('clients', []);
      this.selectClient(null);
    }
  },
  searchClient(query) {
    this.set('clients', this.get('store').query('client', { 'query': query, sort: 'name', 'provider-id': this.get('provider').get('id'), 'page[size]': 10 }));
  },
  selectClient(client) {
    if (client) {
      this.set('client', client)
      if (client.get('isSandbox')) {
        this.get('user').set('sandbox-id', client.id);
      } else {
        this.get('user').set('client', client);
      }
    }
  },

  actions: {
    selectUser(user) {
      this.selectUser(user);
    },
    searchUser(query) {
      this.searchUser(query);
    },
    searchRole() {
      this.searchRole();
    },
    selectRole(role) {
      this.selectRole(role);
    },
    searchProvider(query) {
      this.set('providers', this.get('store').query('provider', { 'query': query, sort: 'name', 'page[size]': 10 }));
    },
    selectProvider(provider) {
      this.selectProvider(provider);
    },
    searchClient(query) {
      this.searchClient(query);
    },
    selectClient(client) {
      this.selectClient(client);
    },
    submit() {
      let self = this;
      if (this.get('client')) {
        this.get('user').set('client', this.get('client'));
        this.get('user').save().then(function(user) {
          self.get('router').transitionTo('clients.show.users', user.get('client'));
        });
      } else if (this.get('provider')) {
        this.get('user').set('provider', this.get('provider'));
        this.get('user').save().then(function(user) {
          self.get('router').transitionTo('providers.show.users', user.get('provider'));
        });
      } else {
        this.get('user').save().then(function() {
          self.get('router').transitionTo('users');
        });
      }
    },
    cancel() {
      if (this.get('client')) {
        this.get('router').transitionTo('clients.show.users', this.get('client'));
      } else if (this.get('provider')) {
        this.get('router').transitionTo('providers.show.users', this.get('provider'));
      } else {
        this.get('router').transitionTo('users');
      }
    }
  }
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';
import Form from './../../../components/form';
import Browser from './browser';

describe('Browser', () => {
  let _window;
  const elem = mount(

  );

  beforeEach(() => {
    _window = {
      location: null
    };
  });

  describe('redirectTo', () => {
    describe('when url is passed', () => {
      const urlsample = 'http://bla';

      it('redirects to url', () => {
        spyOn(Browser, 'getWindow').and.returnValue(_window);

        Browser.redirectTo(urlsample);
        expect(_window.location).toEqual(urlsample);
      });
    });
  });

  describe('isDomAvailable', () => {
    it('returns the window object', () => {
      expect(Browser.isDomAvailable()).toBe(true);
    });
  });

  describe('isDomAvailable when window is undefined', () => {
    it('returns the window object', () => {
      spyOn(Browser, 'getWindow').and.returnValue(undefined);
      expect(Browser.isDomAvailable()).toBe(false);
    });
  });

  describe('isDomAvailable when document is undefined', () => {
    it('returns the window object', () => {
      spyOn(Browser, 'getDocument').and.returnValue(undefined);
      expect(Browser.isDomAvailable()).toBe(false);
    });
  });

  describe('getWindow', () => {
    it('returns the window object', () => {
      expect(Browser.getWindow()).toEqual(window);
    });
  });

  describe('getDocument', () => {
    it('returns the document object', () => {
      expect(Browser.getDocument()).toEqual(document);
    });
  });

  describe('getActiveElement', () => {
    it('returns the document.activeElement', () => {
      expect(Browser.getActiveElement()).toEqual(document.activeElement);
    });
  });

  describe('reload', () => {
    it('calls the windows location relaod method', () => {
      const spy = jasmine.createSpy('reload');
      _window = { location: { reload: spy } };

      spyOn(Browser, 'getWindow').and.returnValue(_window);

      Browser.reload();
      expect(spy).toHaveBeenCalled();
    });
  });

  describe('edit-focus', () => {
    it('focuses on the input field of the passed in ref', () => {
      const node = { focus: jest.fn(), select: jest.fn() }

      spyOn(ReactDOM, 'findDOMNode').and.returnValue(node);
      Browser.editFocus('fakeRef');
      expect(node.focus).toHaveBeenCalled();
      expect(node.select).toHaveBeenCalled();
    });
  });

  describe('setInputFocus', () => {
    it('focuses on the input field of the passed in ref but doesnot select text', () => {
      const node = { focus: jest.fn() }

      let fakeComponent = { _input: {} };
      spyOn(ReactDOM, 'findDOMNode').and.returnValue(node);
      Browser.setInputFocus(fakeComponent);
      expect(node.focus).toHaveBeenCalled();
    });
  });

  describe('cookies', () => {
    afterEach(() => {
      // Remove foo cookie
      Browser.setCookie('foo', 'bar', { expires: 'Thu, 01 Jan 1970 00:00:00 GMT' });
    });

    describe('setCookie', () => {
      it('adds a cookie to the document', () => {
        Browser.setCookie('foo', 'bar');
        expect(Browser.getDocument().cookie).toEqual('foo=bar');
      });

      describe('options', () => {
        describe('when expires is passed', () => {
          it('adds expires date to the cookie', () => {
            const date = new Date();
            date.setDate(date.getDate() + 1);
            Browser.setCookie('foo', 'bar', { expires: date });
            // Cannot check expiration date from document api
            expect(Browser.getDocument().cookie).toEqual('foo=bar');
          });

          it('does not add a cookie when expiration is in the passed', () => {
            const date = new Date();
            date.setDate(date.getDate() - 1);
            Browser.setCookie('foo', 'bar', { expires: date });
            // Cannot check expiration date from document api
            expect(Browser.getDocument().cookie).toEqual('');
          });
        });

        describe('when max-age is passed', () => {
          it('adds expires date to the cookie', () => {
            Browser.setCookie('foo', 'bar', { 'max-age': 1000 });
            // Cannot check expiration date from document api
            expect(Browser.getDocument().cookie).toEqual('foo=bar');
          });
        });
      });
    });

    describe('getCookie', () => {
      describe('when cookie exists', () => {
        it('returns the cookies value', () => {
          Browser.setCookie('foo', 'bar');
          expect(Browser.getCookie('foo')).toEqual('bar');
        });
      });

      describe('when cookie does not exist', () => {
        it('returns null', () => {
          expect(Browser.getCookie('foo')).toBeFalsy();
        });
      });
    });
  });

  describe('postToNewWindow', () => {
    const url = '/foo';
    const key1 = 'foo';
    const value1 = 'foo';
    const key2 = 'bar';
    const value2 = 'bar';
    const data = { [key1]: value1, [key2]: value2 };

    beforeEach(() => {
      spyOn(Browser, 'getDocument').and.returnValue(document);
    });

    describe('when container not found', () => {
      it('creates a container', () => {
        spyOn(document.body, 'appendChild');
        Browser.postToNewWindow(url, { foo: 'bar' });
        expect(document.body.appendChild).toHaveBeenCalled();
      });
    });

    describe('when container found', () => {
      it('does not create a container', () => {
        addPostFormDiv();

        spyOn(document.body, 'appendChild');
        Browser.postToNewWindow(url, data);
        expect(document.body.appendChild).not.toHaveBeenCalled();
      });
    });

    it('renders a form in the container', () => {
      spyOn(React, 'createElement').and.callThrough();
      spyOn(ReactDOM, 'render');

      Browser.postToNewWindow(url, data);

      expect(ReactDOM.render).toHaveBeenCalledWith(
        jasmine.any(Object), // Create Element call
        document.getElementById('carbonPostFormContainer'),
        jasmine.any(Function) // Anon Function
      );

      expect(React.createElement).toHaveBeenCalledWith('form', {
        action: url, method: 'post', target: '_blank'
      }, jasmine.anything());
    });

    it('renders a hidden input for each data member', () => {
      spyOn(React, 'createElement').and.callThrough();
      Browser.postToNewWindow(url, data);
      expect(React.createElement).toHaveBeenCalledWith(
        'input',
        { type: 'hidden', key: key1, name: key1, value: value1 }
      );
      expect(React.createElement).toHaveBeenCalledWith(
        'input',
        { type: 'hidden', key: key2, name: key2, value: value2 }
      );
    });

    it('submits the rendered form', () => {
      spyOn(Browser, 'submitForm');
      Browser.postToNewWindow(url, data);
      expect(Browser.submitForm).toHaveBeenCalled();
    });

    it('unmounts the rendered form', () => {
      spyOn(ReactDOM, 'unmountComponentAtNode').and.callThrough();
      Browser.postToNewWindow(url, data);
      expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalledWith(
        document.getElementById('carbonPostFormContainer')
      );
    });

    describe('when target option is passed', () => {
      it('sets the form target', () => {
        spyOn(React, 'createElement').and.callThrough();
        const target = 'some_window';

        Browser.postToNewWindow(url, data, target);
        expect(React.createElement).toHaveBeenCalledWith('form', {
          action: url, method: 'post', target
        }, jasmine.anything());
      });
    });
  });

  describe('submitForm', () => {
    it('calls submit on the passed form', () => {
      const submitSpy = jasmine.createSpy('form-submit');
      const form = { submit: submitSpy };
      Browser.submitForm(form);
      expect(submitSpy).toHaveBeenCalled();
    });
  });
});

function addPostFormDiv() {
  const div = document.createElement('div');
  div.setAttribute('id', 'carbonPostFormContainer');
  document.body.appendChild(div);
}
<commit_msg>document.create stubbed  and test as undefined<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { mount } from 'enzyme';
import Form from './../../../components/form';
import Browser from './browser';

describe('Browser', () => {
  let _window;
  const elem = mount(

  );

  beforeEach(() => {
    _window = {
      location: null
    };
  });

  describe('redirectTo', () => {
    describe('when url is passed', () => {
      const urlsample = 'http://bla';

      it('redirects to url', () => {
        spyOn(Browser, 'getWindow').and.returnValue(_window);

        Browser.redirectTo(urlsample);
        expect(_window.location).toEqual(urlsample);
      });
    });
  });

  describe('isDomAvailable', () => {
    it('returns the window object', () => {
      expect(Browser.isDomAvailable()).toBe(true);
    });
  });

  describe('isDomAvailable when window is undefined', () => {
    it('returns the window object', () => {
      spyOn(Browser, 'getWindow').and.returnValue(undefined);
      expect(Browser.isDomAvailable()).toBe(false);
    });
  });

  describe('isDomAvailable when document is undefined', () => {
    it('returns the window object', () => {
      spyOn(Browser, 'getDocument').and.returnValue(undefined);
      expect(Browser.isDomAvailable()).toBe(false);
    });
  });

  describe('when document.createElement does not exist', () => {
    it('returns false', () => {
      spyOn(Browser, 'getDocument').and.returnValue({ createElement: undefined });
      expect(Browser.isDomAvailable()).toEqual(false);
    });
  });

  describe('getWindow', () => {
    it('returns the window object', () => {
      expect(Browser.getWindow()).toEqual(window);
    });
  });

  describe('getDocument', () => {
    it('returns the document object', () => {
      expect(Browser.getDocument()).toEqual(document);
    });
  });

  describe('getActiveElement', () => {
    it('returns the document.activeElement', () => {
      expect(Browser.getActiveElement()).toEqual(document.activeElement);
    });
  });

  describe('reload', () => {
    it('calls the windows location relaod method', () => {
      const spy = jasmine.createSpy('reload');
      _window = { location: { reload: spy } };

      spyOn(Browser, 'getWindow').and.returnValue(_window);

      Browser.reload();
      expect(spy).toHaveBeenCalled();
    });
  });

  describe('edit-focus', () => {
    it('focuses on the input field of the passed in ref', () => {
      const node = { focus: jest.fn(), select: jest.fn() }

      spyOn(ReactDOM, 'findDOMNode').and.returnValue(node);
      Browser.editFocus('fakeRef');
      expect(node.focus).toHaveBeenCalled();
      expect(node.select).toHaveBeenCalled();
    });
  });

  describe('setInputFocus', () => {
    it('focuses on the input field of the passed in ref but doesnot select text', () => {
      const node = { focus: jest.fn() }

      let fakeComponent = { _input: {} };
      spyOn(ReactDOM, 'findDOMNode').and.returnValue(node);
      Browser.setInputFocus(fakeComponent);
      expect(node.focus).toHaveBeenCalled();
    });
  });

  describe('cookies', () => {
    afterEach(() => {
      // Remove foo cookie
      Browser.setCookie('foo', 'bar', { expires: 'Thu, 01 Jan 1970 00:00:00 GMT' });
    });

    describe('setCookie', () => {
      it('adds a cookie to the document', () => {
        Browser.setCookie('foo', 'bar');
        expect(Browser.getDocument().cookie).toEqual('foo=bar');
      });

      describe('options', () => {
        describe('when expires is passed', () => {
          it('adds expires date to the cookie', () => {
            const date = new Date();
            date.setDate(date.getDate() + 1);
            Browser.setCookie('foo', 'bar', { expires: date });
            // Cannot check expiration date from document api
            expect(Browser.getDocument().cookie).toEqual('foo=bar');
          });

          it('does not add a cookie when expiration is in the passed', () => {
            const date = new Date();
            date.setDate(date.getDate() - 1);
            Browser.setCookie('foo', 'bar', { expires: date });
            // Cannot check expiration date from document api
            expect(Browser.getDocument().cookie).toEqual('');
          });
        });

        describe('when max-age is passed', () => {
          it('adds expires date to the cookie', () => {
            Browser.setCookie('foo', 'bar', { 'max-age': 1000 });
            // Cannot check expiration date from document api
            expect(Browser.getDocument().cookie).toEqual('foo=bar');
          });
        });
      });
    });

    describe('getCookie', () => {
      describe('when cookie exists', () => {
        it('returns the cookies value', () => {
          Browser.setCookie('foo', 'bar');
          expect(Browser.getCookie('foo')).toEqual('bar');
        });
      });

      describe('when cookie does not exist', () => {
        it('returns null', () => {
          expect(Browser.getCookie('foo')).toBeFalsy();
        });
      });
    });
  });

  describe('postToNewWindow', () => {
    const url = '/foo';
    const key1 = 'foo';
    const value1 = 'foo';
    const key2 = 'bar';
    const value2 = 'bar';
    const data = { [key1]: value1, [key2]: value2 };

    beforeEach(() => {
      spyOn(Browser, 'getDocument').and.returnValue(document);
    });

    describe('when container not found', () => {
      it('creates a container', () => {
        spyOn(document.body, 'appendChild');
        Browser.postToNewWindow(url, { foo: 'bar' });
        expect(document.body.appendChild).toHaveBeenCalled();
      });
    });

    describe('when container found', () => {
      it('does not create a container', () => {
        addPostFormDiv();

        spyOn(document.body, 'appendChild');
        Browser.postToNewWindow(url, data);
        expect(document.body.appendChild).not.toHaveBeenCalled();
      });
    });

    it('renders a form in the container', () => {
      spyOn(React, 'createElement').and.callThrough();
      spyOn(ReactDOM, 'render');

      Browser.postToNewWindow(url, data);

      expect(ReactDOM.render).toHaveBeenCalledWith(
        jasmine.any(Object), // Create Element call
        document.getElementById('carbonPostFormContainer'),
        jasmine.any(Function) // Anon Function
      );

      expect(React.createElement).toHaveBeenCalledWith('form', {
        action: url, method: 'post', target: '_blank'
      }, jasmine.anything());
    });

    it('renders a hidden input for each data member', () => {
      spyOn(React, 'createElement').and.callThrough();
      Browser.postToNewWindow(url, data);
      expect(React.createElement).toHaveBeenCalledWith(
        'input',
        { type: 'hidden', key: key1, name: key1, value: value1 }
      );
      expect(React.createElement).toHaveBeenCalledWith(
        'input',
        { type: 'hidden', key: key2, name: key2, value: value2 }
      );
    });

    it('submits the rendered form', () => {
      spyOn(Browser, 'submitForm');
      Browser.postToNewWindow(url, data);
      expect(Browser.submitForm).toHaveBeenCalled();
    });

    it('unmounts the rendered form', () => {
      spyOn(ReactDOM, 'unmountComponentAtNode').and.callThrough();
      Browser.postToNewWindow(url, data);
      expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalledWith(
        document.getElementById('carbonPostFormContainer')
      );
    });

    describe('when target option is passed', () => {
      it('sets the form target', () => {
        spyOn(React, 'createElement').and.callThrough();
        const target = 'some_window';

        Browser.postToNewWindow(url, data, target);
        expect(React.createElement).toHaveBeenCalledWith('form', {
          action: url, method: 'post', target
        }, jasmine.anything());
      });
    });
  });

  describe('submitForm', () => {
    it('calls submit on the passed form', () => {
      const submitSpy = jasmine.createSpy('form-submit');
      const form = { submit: submitSpy };
      Browser.submitForm(form);
      expect(submitSpy).toHaveBeenCalled();
    });
  });
});

function addPostFormDiv() {
  const div = document.createElement('div');
  div.setAttribute('id', 'carbonPostFormContainer');
  document.body.appendChild(div);
}
<|endoftext|>


<commit_before>/* global document */
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import YouTube from '../';

const videos = [
  { id: 'ZuuVjuLNvFY', name: 'JUNNY - kontra (Feat. Lil Gimch, Keeflow)' },
  { id: 'PYE7jXNjFWw', name: 'T W L V - Follow' },
  { id: 'ld8ugY47cps', name: 'SLCHLD - I can\'t love you anymore' },
  { id: null, name: '<none>' },
];

const qualities = ['auto', '240', '380', '480', '720', '1080', '1440', '2160'];

const hashVideoRx = /^#!\/video\/(\d)$/
const defaultVideo = hashVideoRx.test(location.hash) ?
  parseInt(location.hash.replace(hashVideoRx, '$1'), 10) :
  0;

class App extends React.Component {
  state = {
    video: defaultVideo,
    suggestedQuality: 'auto',
    volume: 1,
    paused: false,
  };

  selectVideo(index) {
    this.setState({ video: index });
  }

  handlePause = (event) => {
    this.setState({
      paused: event.target.checked,
    });
  };

  handlePlayerPause = () => {
    this.setState({ paused: true });
  };
  handlePlayerPlay = () => {
    this.setState({ paused: false });
  };

  handleVolume = (event) => {
    this.setState({
      volume: parseFloat(event.target.value),
    });
  };

  handleQuality = (event) => {
    this.setState({
      suggestedQuality: qualities[event.target.selectedIndex],
    });
  };

  render() {
    const video = videos[this.state.video];
    return (

Video

            {videos.map((choice, index) => (
              <a
                href={`#!/video/${index}`}
                className={`collection-item ${video === choice ? 'active' : ''}`}
                onClick={() => this.selectVideo(index)}
              >
                {choice.name}

            ))}

Paused

            <input
              type="checkbox"
              id="paused"
              checked={this.state.paused}
              onChange={this.handlePause}
            />

              Paused

Volume

          <input
            type="range"
            value={this.state.volume}
            min={0}
            max={1}
            step={0.01}
            onChange={this.handleVolume}
          />

Quality

          <select className="browser-default" onChange={this.handleQuality}>
            {qualities.map(quality => (
              <option value={quality}>{quality}</option>
            ))}
          </select>

          <YouTube
            video={video.id}
            width={640}
            height={480}
            autoplay
            controls={false}
            suggestedQuality={this.state.suggestedQuality}
            volume={this.state.volume}
            paused={this.state.paused}
            onPause={this.handlePlayerPause}
            onPlay={this.handlePlayerPlay}
          />

    );
  }
}

ReactDOM.render(<App />, document.getElementById('example'));
<commit_msg>example: Fix warnings about keys and PropTypes<commit_after>/* global document */
import React from 'react';
import ReactDOM from 'react-dom';
import YouTube from '../';

const videos = [
  { id: 'ZuuVjuLNvFY', name: 'JUNNY - kontra (Feat. Lil Gimch, Keeflow)' },
  { id: 'PYE7jXNjFWw', name: 'T W L V - Follow' },
  { id: 'ld8ugY47cps', name: 'SLCHLD - I can\'t love you anymore' },
  { id: null, name: '<none>' },
];

const qualities = ['auto', '240', '380', '480', '720', '1080', '1440', '2160'];

const hashVideoRx = /^#!\/video\/(\d)$/
const defaultVideo = hashVideoRx.test(location.hash) ?
  parseInt(location.hash.replace(hashVideoRx, '$1'), 10) :
  0;

class App extends React.Component {
  state = {
    video: defaultVideo,
    suggestedQuality: 'auto',
    volume: 1,
    paused: false,
  };

  selectVideo(index) {
    this.setState({ video: index });
  }

  handlePause = (event) => {
    this.setState({
      paused: event.target.checked,
    });
  };

  handlePlayerPause = () => {
    this.setState({ paused: true });
  };
  handlePlayerPlay = () => {
    this.setState({ paused: false });
  };

  handleVolume = (event) => {
    this.setState({
      volume: parseFloat(event.target.value),
    });
  };

  handleQuality = (event) => {
    this.setState({
      suggestedQuality: qualities[event.target.selectedIndex],
    });
  };

  render() {
    const video = videos[this.state.video];
    return (

Video

            {videos.map((choice, index) => (
              <a
                key={choice.id}
                href={`#!/video/${index}`}
                className={`collection-item ${video === choice ? 'active' : ''}`}
                onClick={() => this.selectVideo(index)}
              >
                {choice.name}

            ))}

Paused

            <input
              type="checkbox"
              id="paused"
              checked={this.state.paused}
              onChange={this.handlePause}
            />

              Paused

Volume

          <input
            type="range"
            value={this.state.volume}
            min={0}
            max={1}
            step={0.01}
            onChange={this.handleVolume}
          />

Quality

          <select className="browser-default" onChange={this.handleQuality}>
            {qualities.map(quality => (
              <option key={quality} value={quality}>{quality}</option>
            ))}
          </select>

          <YouTube
            video={video.id}
            width={640}
            height={480}
            autoplay
            controls={false}
            suggestedQuality={this.state.suggestedQuality}
            volume={this.state.volume}
            paused={this.state.paused}
            onPause={this.handlePlayerPause}
            onPlay={this.handlePlayerPlay}
          />

    );
  }
}

ReactDOM.render(<App />, document.getElementById('example'));
<|endoftext|>


<commit_before>'use strict'

var MissingArgumentError = require('./errors/MissingArgumentError')

module.exports = ConnectSequence

/**
 * @class
 * @param {Array<Function>} [middlewareList] A list of middlewares to run
 * @param {object} req The request object
 * @param {object} res The response object
 * @param {function} next The next middleware
 * @returns {undefined}
 */
function ConnectSequence (req, res, next) {
  var errorMsg
  if (arguments.length < 3) {
    errorMsg = 'ConnectSequence#run() takes 3 arguments. '
    errorMsg += arguments.length + ' given.'
    throw new MissingArgumentError(errorMsg)
  }
  if (typeof req !== 'object') {
    errorMsg = 'The first argument must be a request object. '
    errorMsg += typeof req + ' given.'
    throw new TypeError(errorMsg)
  }
  if (typeof res !== 'object') {
    errorMsg = 'The second argument must be a request object. '
    errorMsg += typeof req + ' given.'
    throw new TypeError(errorMsg)
  }
  if (typeof next !== 'function') {
    errorMsg = 'The third argument must be a middleware function. '
    errorMsg += typeof req + ' given.'
    throw new TypeError(errorMsg)
  }

  this.req = req
  this.res = res
  this.next = next
  this.middlewares = []
}

ConnectSequence.prototype = {
  append: append,
  appendList: appendList,
  appendIf: appendIf,
  appendListIf: appendListIf,
  run: run
}

/**
 * Run sequencially each appended middleware, using the next argument as the final callback.
 * @method
 * @returns {undefined}
 */
function run () {
  var midSequence = this.middlewares.reverse()
  var initialNext = this.next.bind()
  var req = this.req
  var res = this.res
  var nestedCallSequence

  // create the call sequence
  nestedCallSequence = midSequence.reduce(middlewareReducer, initialNext)
  // call it
  nestedCallSequence.call()

  /**
   * Reduce the middleware sequence to a nested middleware handler sequence
   * @function
   * @param {Function} callSequence intermediate resulting call sequence
   * @param {Function} middleware the current middleware
   * @returns {Function} the new intermediate resulting call sequence
   */
  function middlewareReducer (callSequence, middleware) {
    return function nextHandler (err) {
      // if the previous middleware passed an error argument
      if (err !== undefined) {
        if (isErrorHandler(middleware)) {
          // call the current middleware if it is an error handler middleware
          middleware(err, req, res, callSequence)
        } else {
          // else skip the current middleware and call the intermediate sequence
          callSequence(err)
        }
      } else {
        // if no error argument is passed
        if (isErrorHandler(middleware)) {
          // skip the current middleware if it is an errorHandler
          callSequence()
        } else {
          // else call it
          middleware(req, res, callSequence)
        }
      }
    }
  }
}

/**
 * Append an arbitrary number of middlewares as argument list or as an array
 * @method
 * @param {...Function} middlewares a list of middlewares
 * @throws TypeError if one of the given middlewares is not a function. All the given middlewares would be rejected.
 */
function append (/* mid_0, ..., mid_n */) {
  var i
  for (i = 0; i < arguments.length; i++) {
    if (typeof arguments[i] !== 'function') {
      var type = typeof arguments[i]
      var errMsg = 'Given middlewares must be functions. "' + type + '" given.'
      throw new TypeError(errMsg)
    }
  }
  for (i = 0; i < arguments.length; i++) {
    this.middlewares.push(arguments[i])
  }
  return this
}

/**
 * Append many middlewares in an array
 * @method
 * @param {Array<Function>} middlewares
 */
function appendList (middlewares) {
  if (!Array.isArray(middlewares)) {
    var errorMsg = 'First argument must be an array of middlewares. '
    errorMsg += typeof middlewares + ' given.'
    throw new TypeError(errorMsg)
  }
  return this.append.apply(this, middlewares)
}

/**
 * Append a list of middlewares as argument list if the filter pass the first time
 * @method
 * @param {Function} filter A filter function (returning a Boolean)
 * @param {Function} middlewares A middleware list of functions (calling its third argument as callback)
 * @returns {undefined}
 */
function appendIf (filter /*, middlewares */) {
  var errorMsg
  var middlewares = []

  if (arguments.length < 2) {
    errorMsg = 'ConnectSequence#appendIf() takes 2 arguments. '
    errorMsg += arguments.length + ' given.'
    throw new MissingArgumentError(errorMsg)
  }
  if (typeof filter !== 'function') {
    errorMsg = 'The first argument must be a filter function. '
    errorMsg += typeof filter + ' given.'
    throw new TypeError(errorMsg)
  }

  var middleware, i
  for (i = 1; i < arguments.length; i++) {
    middleware = arguments[i]
    if (typeof middleware !== 'function') {
      errorMsg = 'The second argument must be a middleware function. '
      errorMsg += typeof middleware + ' given.'
      throw new TypeError(errorMsg)
    }
    middlewares.push(middleware)
  }

  var firstMiddleware = middlewares[0]
  if (isErrorHandler(firstMiddleware)) {
    this.append(function (err, req, res, next) {
      req.__connectSequenceFilterValue = filter(req)
      if (req.__connectSequenceFilterValue) {
        firstMiddleware(err, req, res, next)
      } else {
        next()
      }
    })
  } else {
    this.append(function (req, res, next) {
      req.__connectSequenceFilterValue = filter(req)
      if (req.__connectSequenceFilterValue) {
        firstMiddleware(req, res, next)
      } else {
        next()
      }
    })
  }

  for (i = 1; i < middlewares.length; i++) {
    middleware = middlewares[i]
    appendOnFilterValue.call(this, middleware)
  }

  return this
}

/**
 * Append many middlewares in an array if the filter pass the first time
 * @method
 * @param {Function} filter A filter function on the req object
 * @param {Array<Function>} middlewares An array of middlewares to append to the sequence
 * @return {ConnectSequence} a reference to the instance to be chainable
 */
function appendListIf (filter, middlewares) {
  var args = [filter]
  for (var i = 0; i < middlewares.length; i++) {
    args.push(middlewares[i])
  }
  return this.appendIf.apply(this, args)
}

/**
 * Tells if a given middleware is a regular middleware or an error handler
 * @function
 * @inner
 * @param {Function} middleware
 * @returns {Boolean}
 */
function isErrorHandler (cb) {
  var str = cb.toString()
  var args = str.split('(')[1].split(')')[0].split(',')
  return args.length === 4
}

/**
 * Append a middleware in function of its nature and the filter value stored in req.__connectSequenceFilterValue
 * @function
 * @inner
 * @param {Function} middleware
 * @returns {undefined}
 */
function appendOnFilterValue (middleware) {
  if (isErrorHandler(middleware)) {
    this.append(function (err, req, res, next) {
      if (req.__connectSequenceFilterValue) {
        middleware(err, req, res, next)
      } else {
        next()
      }
    })
  } else {
    this.append(function (req, res, next) {
      if (req.__connectSequenceFilterValue) {
        middleware(req, res, next)
      } else {
        next()
      }
    })
  }
}
<commit_msg>improve jsdoc<commit_after>'use strict'

var MissingArgumentError = require('./errors/MissingArgumentError')

module.exports = ConnectSequence

/**
 * @class
 * @param {Array<Function>} [middlewareList] A list of middlewares to run
 * @param {object} req The request object
 * @param {object} res The response object
 * @param {function} next The next middleware
 * @returns {undefined}
 */
function ConnectSequence (req, res, next) {
  var errorMsg
  if (arguments.length < 3) {
    errorMsg = 'ConnectSequence#run() takes 3 arguments. '
    errorMsg += arguments.length + ' given.'
    throw new MissingArgumentError(errorMsg)
  }
  if (typeof req !== 'object') {
    errorMsg = 'The first argument must be a request object. '
    errorMsg += typeof req + ' given.'
    throw new TypeError(errorMsg)
  }
  if (typeof res !== 'object') {
    errorMsg = 'The second argument must be a request object. '
    errorMsg += typeof req + ' given.'
    throw new TypeError(errorMsg)
  }
  if (typeof next !== 'function') {
    errorMsg = 'The third argument must be a middleware function. '
    errorMsg += typeof req + ' given.'
    throw new TypeError(errorMsg)
  }

  this.req = req
  this.res = res
  this.next = next
  this.middlewares = []
}

ConnectSequence.prototype = {
  append: append,
  appendList: appendList,
  appendIf: appendIf,
  appendListIf: appendListIf,
  run: run
}

/**
 * Run sequencially each appended middleware, using the next argument as the final callback.
 * @method
 * @memberof ConnectSequence.prototype
 * @returns {undefined}
 */
function run () {
  var midSequence = this.middlewares.reverse()
  var initialNext = this.next.bind()
  var req = this.req
  var res = this.res
  var nestedCallSequence

  // create the call sequence
  nestedCallSequence = midSequence.reduce(middlewareReducer, initialNext)
  // call it
  nestedCallSequence.call()

  /**
   * Reduce the middleware sequence to a nested middleware handler sequence
   * @function
   * @inner
   * @private
   * @param {Function} callSequence intermediate resulting call sequence
   * @param {Function} middleware the current middleware
   * @returns {Function} the new intermediate resulting call sequence
   */
  function middlewareReducer (callSequence, middleware) {
    return function nextHandler (err) {
      // if the previous middleware passed an error argument
      if (err !== undefined) {
        if (isErrorHandler(middleware)) {
          // call the current middleware if it is an error handler middleware
          middleware(err, req, res, callSequence)
        } else {
          // else skip the current middleware and call the intermediate sequence
          callSequence(err)
        }
      } else {
        // if no error argument is passed
        if (isErrorHandler(middleware)) {
          // skip the current middleware if it is an errorHandler
          callSequence()
        } else {
          // else call it
          middleware(req, res, callSequence)
        }
      }
    }
  }
}

/**
 * Append an arbitrary number of middlewares as argument list or as an array
 * @method
 * @memberof ConnectSequence.prototype
 * @param {...Function} middlewares a list of middlewares
 * @return {ConnectSequence} a reference to the instance to be chainable
 * @throws TypeError if one of the given middlewares is not a function. All the given middlewares would be rejected.
 */
function append (/* mid_0, ..., mid_n */) {
  var i
  for (i = 0; i < arguments.length; i++) {
    if (typeof arguments[i] !== 'function') {
      var type = typeof arguments[i]
      var errMsg = 'Given middlewares must be functions. "' + type + '" given.'
      throw new TypeError(errMsg)
    }
  }
  for (i = 0; i < arguments.length; i++) {
    this.middlewares.push(arguments[i])
  }
  return this
}

/**
 * Append many middlewares in an array
 * @method
 * @memberof ConnectSequence.prototype
 * @param {Array<Function>} middlewares
 * @return {ConnectSequence} a reference to the instance to be chainable
 */
function appendList (middlewares) {
  if (!Array.isArray(middlewares)) {
    var errorMsg = 'First argument must be an array of middlewares. '
    errorMsg += typeof middlewares + ' given.'
    throw new TypeError(errorMsg)
  }
  return this.append.apply(this, middlewares)
}

/**
 * Append a list of middlewares as argument list if the filter pass the first time
 * @method
 * @memberof ConnectSequence.prototype
 * @param {Function} filter A filter function (returning a Boolean)
 * @param {Function} middlewares A middleware list of functions (calling its third argument as callback)
 * @return {ConnectSequence} a reference to the instance to be chainable
 */
function appendIf (filter /*, middlewares */) {
  var errorMsg
  var middlewares = []

  if (arguments.length < 2) {
    errorMsg = 'ConnectSequence#appendIf() takes 2 arguments. '
    errorMsg += arguments.length + ' given.'
    throw new MissingArgumentError(errorMsg)
  }
  if (typeof filter !== 'function') {
    errorMsg = 'The first argument must be a filter function. '
    errorMsg += typeof filter + ' given.'
    throw new TypeError(errorMsg)
  }

  var middleware, i
  for (i = 1; i < arguments.length; i++) {
    middleware = arguments[i]
    if (typeof middleware !== 'function') {
      errorMsg = 'The second argument must be a middleware function. '
      errorMsg += typeof middleware + ' given.'
      throw new TypeError(errorMsg)
    }
    middlewares.push(middleware)
  }

  var firstMiddleware = middlewares[0]
  if (isErrorHandler(firstMiddleware)) {
    this.append(function (err, req, res, next) {
      req.__connectSequenceFilterValue = filter(req)
      if (req.__connectSequenceFilterValue) {
        firstMiddleware(err, req, res, next)
      } else {
        next()
      }
    })
  } else {
    this.append(function (req, res, next) {
      req.__connectSequenceFilterValue = filter(req)
      if (req.__connectSequenceFilterValue) {
        firstMiddleware(req, res, next)
      } else {
        next()
      }
    })
  }

  for (i = 1; i < middlewares.length; i++) {
    middleware = middlewares[i]
    appendOnFilterValue.call(this, middleware)
  }

  return this
}

/**
 * Append many middlewares in an array if the filter pass the first time
 * @method
 * @memberof ConnectSequence.prototype
 * @param {Function} filter A filter function on the req object
 * @param {Array<Function>} middlewares An array of middlewares to append to the sequence
 * @return {ConnectSequence} a reference to the instance to be chainable
 */
function appendListIf (filter, middlewares) {
  var args = [filter]
  for (var i = 0; i < middlewares.length; i++) {
    args.push(middlewares[i])
  }
  return this.appendIf.apply(this, args)
}

/**
 * Tells if a given middleware is a regular middleware or an error handler
 * @function
 * @inner
 * @private
 * @param {Function} middleware
 * @returns {Boolean}
 */
function isErrorHandler (cb) {
  var str = cb.toString()
  var args = str.split('(')[1].split(')')[0].split(',')
  return args.length === 4
}

/**
 * Append a middleware in function of its nature and the filter value stored in req.__connectSequenceFilterValue
 * @function
 * @inner
 * @private
 * @param {Function} middleware
 * @returns {undefined}
 */
function appendOnFilterValue (middleware) {
  if (isErrorHandler(middleware)) {
    this.append(function (err, req, res, next) {
      if (req.__connectSequenceFilterValue) {
        middleware(err, req, res, next)
      } else {
        next()
      }
    })
  } else {
    this.append(function (req, res, next) {
      if (req.__connectSequenceFilterValue) {
        middleware(req, res, next)
      } else {
        next()
      }
    })
  }
}
<|endoftext|>


<commit_before>if (typeof module !== 'undefined')
	require('${basedir}/target/src/javascript/mqttws31n.js');
var testServer = "${test.server}";
var testPort = parseInt("${test.server.port}");
var testPath = "${test.server.path}";

var genStr = function(str){
	return str + Math.floor(Math.random()*100)
};

describe('BasicTest', function() {
	//var client = null;
	var clientId = this.description;
	//console.log('...',this.description);
	var connected = false;
	var failure = false;
	var disconnectError = null;
	var disconnectErrorMsg = null;

	var subscribed = false;
	var isMessageReceived = false;
	var isMessageDelivered = false;
	var strTopic = '/World';
	var strMessageReceived = '';
	var strMessageSend = 'Hello';
	var strTopicReceived = '';

	function onConnectSuccess(responseObj) {
		//console.log("connected %s",responseObj);
		connected = true;
	};

	function onConnectionLost(err) {
		connected = false;
		if(err){
			disconnectError = err.errorCode;
			disconnectErrorMsg = err.errorMessage;
		}
		console.log("connection lost. ErrorCode: %s, ErrorMsg: %s",disconnectError,disconnectErrorMsg);
	};

	function onConnectFailure(err){
		connected = false;
		console.log('Connect fail. ErrorCode: %s, ErrorMsg: %s',err.errCode,err.errorMessage);
	};

	function onSubscribeSuccess() {
		subscribed = true;
		//console.log("subscribed",subscribed);
	};

	function onSubscribeFailure(err) {
		subscribed = false;
		console.log("subscrib fail. ErrorCode: %s, ErrorMsg: %s",err.errCode,err.errorMessage);
	};
	function onUnsubscribeSuccess() {
		subscribed = false;
		//console.log("unsubscribed",subscribed);
	};

	function messageDelivered(response) {
		console.log("messageDelivered. topic:%s, duplicate:%s, payloadString:%s,qos:%s,retained:%s",response.destinationName,response.duplicate,response.payloadString,response.qos,response.retained);
		isMessageDelivered = true;
		//reponse.invocationContext.onMessageArrived = null;
	};

	function messageArrived(message) {
		console.log("messageArrived.",'topic:',message.destinationName,' ;content:',message.payloadString);
		isMessageReceived = true;
		strMessageReceived = message.payloadString;
		strTopicReceived = message.destinationName;

		//reponse.invocationContext.onMessageArrived = null;
	};

	beforeEach(function(){
		connected = false;
		failure = false;
		disconnectError = null;
		disconnectErrorMsg = null;
		//if(!client){
		//	client = new Messaging.Client(testServer, testPort, clientId);
		//}
	});

	/*afterEach(function(){
		if(client){
			client.disconnect();
		}
	});
	*/
	it('it should create and connect and disconnect to a server.', function() {
		var client = new Messaging.Client(testServer, testPort, testPath, genStr(clientId));
		client.onConnectionLost = onConnectionLost;
		expect(client).not.toBe(null);

		console.log('Connecting...');
		runs(function() {
			client.connect({onSuccess:onConnectSuccess});
		});
		waitsFor(function() {
			return connected;
		}, "the client should connect", 2000);
		runs(function() {
			expect(connected).toBe(true);
		});

		console.log('Disconnecting...');
		runs(function() {
			client.disconnect();
		});
		waitsFor(function() {
			return (connected==false);
		}, "the client should disconnect", 2000);
		runs(function() {
			expect(connected).not.toBe(true);
		});

		console.log('Re-Connecting...');
		runs(function() {
			client.connect({onSuccess:onConnectSuccess});
		});

		waitsFor(function() {
			return connected;
		}, "the client should re-connect", 2000);

		runs(function() {
			expect(connected).toBe(true);
		});

	});

	it('it should connect to a list of server(HA connection).',function(){
		var defaultServer = testServer;
		var defaultPort = testPort;
		var arrHosts = ["127.0.0.1",testServer,];
		var arrPorts = [1882,testPort];

		var client = new Messaging.Client(defaultServer, defaultPort, testPath, genStr(clientId) );
		client.onConnectionLost = onConnectionLost;
		expect(client).not.toBe(null);

		console.log('should connect to a available server from list');
		runs(function() {
			client.connect({
				onSuccess : onConnectSuccess,
				onFailure : onConnectFailure,
				hosts : arrHosts,
				ports : arrPorts
			});
		});

		waitsFor(function() {
			return connected;
		}, "the client should connect", 2000);

		runs(function() {
			expect(connected).toBe(true);
			//client.disconnect();
		});

	});

	it('it should publish and subscribe.',function(){

		var client = new Messaging.Client(testServer, testPort, testPath, genStr(clientId));
		client.onMessageArrived = messageArrived;
		client.onMessageDelivered = messageDelivered;

		runs(function() {
			client.connect({onSuccess:onConnectSuccess,onFailure:onConnectFailure});
		});
		waitsFor(function() {
			return connected;
		}, "the client should connect", 2000);
		runs(function() {
			expect(connected).toBe(true);
		});

		console.log('Subscribe a topic...');
		runs(function() {
			client.subscribe(strTopic, {onSuccess:onSubscribeSuccess,onFailure:onSubscribeFailure});
		});

		waitsFor(function() {
			return subscribed;
		}, "the client should subscribe", 2000);

		runs(function() {
			expect(subscribed).toBe(true);
		});

		console.log('Send and receive message...');
		runs(function() {
			var message = new Messaging.Message(strMessageSend);
			message.destinationName = strTopic;
			client.send(message);
		});
		waitsFor(function() {
			return isMessageReceived;
		}, "the client should send and receive a message", 2000);
		runs(function() {
			//to do Check message sent
			expect(isMessageDelivered).toBe(true);
			//Check msg received
			expect(isMessageReceived).toBe(true);
			//Check message
			expect(strMessageReceived).toEqual(strMessageSend);
			//Check topic
			expect(strTopicReceived).toEqual(strTopic);

			//disconnect
			//client.disconnect();

		});

		console.log('Unsubscribe a topic...');
		runs(function() {
			client.unsubscribe(strTopic, {onSuccess:onUnsubscribeSuccess});
		});
	    waitsFor(function() {
			return !subscribed;
		}, "the client should subscribe", 2000);
		runs(function() {
			expect(subscribed).toBe(false);
			//disconnect
			//client.disconnect();
		});

		//should not receive a message after unsubscribe
		runs(function() {
			//console.log('isMessageReceived',isMessageReceived);
			isMessageDelivered = false;
			isMessageReceived = false;
			strMessageReceived = '';
			strTopicReceived = '';

			var message = new Messaging.Message(genStr(strMessageSend));
			message.destinationName = strTopic;
			client.send(message);
		})
		waitsFor(function() {
			return isMessageDelivered;
		}, "the client should send and receive a message", 2000);

		runs(function() {
			//to do Check message sent
			expect(isMessageDelivered).toBe(true);
			//Check msg received
			expect(isMessageReceived).toBe(false);
			//Check message
			expect(strMessageReceived).toEqual('');
			//Check topic
			expect(strTopicReceived).toEqual('');

			//disconnect
			//client.disconnect();

		})
	});

	it('check message properties.',function(){
		var strMsg = 'test Msg';
		var strDes = '/test';
		var message = new Messaging.Message(strMsg);
		message.destinationName = strDes;

		console.log('Check default for message with payload.');
		expect(message.qos).toBe(0);
		expect(message.duplicate).toBe(false);
		expect(message.retained).toBe(false);
		expect(message.payloadString).toEqual(strMsg);
		expect(message.payloadBytes.length).toBeGreaterThan(0);
		expect(message.destinationName).toEqual(strDes);

		console.log('Check empty msg to throw error');
		expect(function(){
			var empMsg = new Messaging.Message();
		}).toThrow();

		console.log('Check message qos');
		message.qos = 0;
		expect(message.qos).toBe(0);
		message.qos = 1;
		expect(message.qos).toBe(1);
		message.qos = 2;
		expect(message.qos).toBe(2);

		//illegal argument exception
		expect(function(){
			message.qos = -1;
		}).toThrow();
		expect(function(){
			message.qos = 1;
		}).not.toThrow();

		console.log('Check payload');
		var strPayload = 'payload is a string';
		message.payloadString = strPayload;
		console.log('not allowed to set payload');
		expect(message.payloadString).not.toEqual(strPayload);

		console.log('Check retained');
		message.retained = false;
		expect(message.retained).toBe(false);
		message.retained = true;
		expect(message.retained).toBe(true);

		console.log('Check duplicate');
		message.duplicate = false;
		expect(message.duplicate).toBe(false);
		message.duplicate = true;
		expect(message.duplicate).toBe(true);

		//to do , check payload
		/*
		var buffer = new ArrayBuffer(4);
		var uintArr = new Uint8Array(buffer);
		dataView = new DataView(buffer);
		dataView.setInt32(0,0x48656c6c);
		//dataView.setInt
		console.log(dataView.getInt32(0).toString(16));
		//var arrbufPayload = new ArrayBuffer
		var msg = new Messaging.Message(buffer);
		console.log(msg.payloadBytes,msg.payloadString);
		*/
	});

});

	<commit_msg>update to genstr function<commit_after>if (typeof module !== 'undefined')
	require('${basedir}/target/src/javascript/mqttws31n.js');
var testServer = "${test.server}";
var testPort = parseInt("${test.server.port}");
var testPath = "${test.server.path}";

var genStr = function(str){
	var time = new Date();
	return str + '.' + time.getTime();
};

describe('BasicTest', function() {
	//var client = null;
	var clientId = this.description;
	//console.log('...',this.description);
	var connected = false;
	var failure = false;
	var disconnectError = null;
	var disconnectErrorMsg = null;

	var subscribed = false;
	var isMessageReceived = false;
	var isMessageDelivered = false;
	var strTopic = '/World';
	var strMessageReceived = '';
	var strMessageSend = 'Hello';
	var strTopicReceived = '';

	function onConnectSuccess(responseObj) {
		//console.log("connected %s",responseObj);
		connected = true;
	};

	function onConnectionLost(err) {
		connected = false;
		if(err){
			disconnectError = err.errorCode;
			disconnectErrorMsg = err.errorMessage;
		}
		console.log("connection lost. ErrorCode: %s, ErrorMsg: %s",disconnectError,disconnectErrorMsg);
	};

	function onConnectFailure(err){
		connected = false;
		console.log('Connect fail. ErrorCode: %s, ErrorMsg: %s',err.errCode,err.errorMessage);
	};

	function onSubscribeSuccess() {
		subscribed = true;
		//console.log("subscribed",subscribed);
	};

	function onSubscribeFailure(err) {
		subscribed = false;
		console.log("subscrib fail. ErrorCode: %s, ErrorMsg: %s",err.errCode,err.errorMessage);
	};
	function onUnsubscribeSuccess() {
		subscribed = false;
		//console.log("unsubscribed",subscribed);
	};

	function messageDelivered(response) {
		console.log("messageDelivered. topic:%s, duplicate:%s, payloadString:%s,qos:%s,retained:%s",response.destinationName,response.duplicate,response.payloadString,response.qos,response.retained);
		isMessageDelivered = true;
		//reponse.invocationContext.onMessageArrived = null;
	};

	function messageArrived(message) {
		console.log("messageArrived.",'topic:',message.destinationName,' ;content:',message.payloadString);
		isMessageReceived = true;
		strMessageReceived = message.payloadString;
		strTopicReceived = message.destinationName;

		//reponse.invocationContext.onMessageArrived = null;
	};

	beforeEach(function(){
		connected = false;
		failure = false;
		disconnectError = null;
		disconnectErrorMsg = null;
		//if(!client){
		//	client = new Messaging.Client(testServer, testPort, clientId);
		//}
	});

	/*afterEach(function(){
		if(client){
			client.disconnect();
		}
	});
	*/
	it('it should create and connect and disconnect to a server.', function() {
		var client = new Messaging.Client(testServer, testPort, testPath, genStr(clientId));
		client.onConnectionLost = onConnectionLost;
		expect(client).not.toBe(null);

		console.log('Connecting...');
		runs(function() {
			client.connect({onSuccess:onConnectSuccess,onFailure:onConnectFailure});
		});
		waitsFor(function() {
			return connected;
		}, "the client should connect", 2000);
		runs(function() {
			expect(connected).toBe(true);
		});

		console.log('Disconnecting...');
		runs(function() {
			client.disconnect();
		});
		waitsFor(function() {
			return (connected==false);
		}, "the client should disconnect", 2000);
		runs(function() {
			expect(connected).not.toBe(true);
		});

		console.log('Re-Connecting...');
		runs(function() {
			client.connect({onSuccess:onConnectSuccess});
		});

		waitsFor(function() {
			return connected;
		}, "the client should re-connect", 2000);

		runs(function() {
			expect(connected).toBe(true);
		});

	});

	it('it should connect to a list of server(HA connection).',function(){
		var defaultServer = testServer;
		var defaultPort = testPort;
		var arrHosts = ['localhost',testServer,];
		var arrPorts = [1883,testPort];

		var client = new Messaging.Client(defaultServer, defaultPort, testPath, genStr(clientId) );
		client.onConnectionLost = onConnectionLost;
		expect(client).not.toBe(null);

		console.log('should connect to a available server from list');
		runs(function() {
			client.connect({
				onSuccess : onConnectSuccess,
				onFailure : onConnectFailure,
				hosts : arrHosts,
				ports : arrPorts
			});
		});

		waitsFor(function() {
			return connected;
		}, "the client should connect", 2000);

		runs(function() {
			expect(connected).toBe(true);
			//client.disconnect();
		});

	});

	it('it should publish and subscribe.',function(){

		var client = new Messaging.Client(testServer, testPort, testPath, genStr(clientId));
		client.onMessageArrived = messageArrived;
		client.onMessageDelivered = messageDelivered;

		runs(function() {
			client.connect({onSuccess:onConnectSuccess,onFailure:onConnectFailure});
		});
		waitsFor(function() {
			return connected;
		}, "the client should connect", 2000);
		runs(function() {
			expect(connected).toBe(true);
		});

		console.log('Subscribe a topic...');
		runs(function() {
			client.subscribe(strTopic, {onSuccess:onSubscribeSuccess,onFailure:onSubscribeFailure});
		});

		waitsFor(function() {
			return subscribed;
		}, "the client should subscribe", 2000);

		runs(function() {
			expect(subscribed).toBe(true);
		});

		console.log('Send and receive message...');
		runs(function() {
			var message = new Messaging.Message(strMessageSend);
			message.destinationName = strTopic;
			client.send(message);
		});
		waitsFor(function() {
			return isMessageReceived;
		}, "the client should send and receive a message", 2000);
		runs(function() {
			//to do Check message sent
			expect(isMessageDelivered).toBe(true);
			//Check msg received
			expect(isMessageReceived).toBe(true);
			//Check message
			expect(strMessageReceived).toEqual(strMessageSend);
			//Check topic
			expect(strTopicReceived).toEqual(strTopic);

			//disconnect
			//client.disconnect();

		});

		console.log('Unsubscribe a topic...');
		runs(function() {
			client.unsubscribe(strTopic, {onSuccess:onUnsubscribeSuccess});
		});
	    waitsFor(function() {
			return !subscribed;
		}, "the client should subscribe", 2000);
		runs(function() {
			expect(subscribed).toBe(false);
			//disconnect
			//client.disconnect();
		});

		//should not receive a message after unsubscribe
		runs(function() {
			//console.log('isMessageReceived',isMessageReceived);
			isMessageDelivered = false;
			isMessageReceived = false;
			strMessageReceived = '';
			strTopicReceived = '';

			var message = new Messaging.Message(genStr(strMessageSend));
			message.destinationName = strTopic;
			client.send(message);
		})
		waitsFor(function() {
			return isMessageDelivered;
		}, "the client should send and receive a message", 2000);

		runs(function() {
			//to do Check message sent
			expect(isMessageDelivered).toBe(true);
			//Check msg received
			expect(isMessageReceived).toBe(false);
			//Check message
			expect(strMessageReceived).toEqual('');
			//Check topic
			expect(strTopicReceived).toEqual('');

			//disconnect
			//client.disconnect();

		})
	});

	it('check message properties.',function(){
		var strMsg = 'test Msg';
		var strDes = '/test';
		var message = new Messaging.Message(strMsg);
		message.destinationName = strDes;

		console.log('Check default for message with payload.');
		expect(message.qos).toBe(0);
		expect(message.duplicate).toBe(false);
		expect(message.retained).toBe(false);
		expect(message.payloadString).toEqual(strMsg);
		expect(message.payloadBytes.length).toBeGreaterThan(0);
		expect(message.destinationName).toEqual(strDes);

		console.log('Check empty msg to throw error');
		expect(function(){
			var empMsg = new Messaging.Message();
		}).toThrow();

		console.log('Check message qos');
		message.qos = 0;
		expect(message.qos).toBe(0);
		message.qos = 1;
		expect(message.qos).toBe(1);
		message.qos = 2;
		expect(message.qos).toBe(2);

		//illegal argument exception
		expect(function(){
			message.qos = -1;
		}).toThrow();
		expect(function(){
			message.qos = 1;
		}).not.toThrow();

		console.log('Check payload');
		var strPayload = 'payload is a string';
		message.payloadString = strPayload;
		console.log('not allowed to set payload');
		expect(message.payloadString).not.toEqual(strPayload);

		console.log('Check retained');
		message.retained = false;
		expect(message.retained).toBe(false);
		message.retained = true;
		expect(message.retained).toBe(true);

		console.log('Check duplicate');
		message.duplicate = false;
		expect(message.duplicate).toBe(false);
		message.duplicate = true;
		expect(message.duplicate).toBe(true);

		//to do , check payload
		/*
		var buffer = new ArrayBuffer(4);
		var uintArr = new Uint8Array(buffer);
		dataView = new DataView(buffer);
		dataView.setInt32(0,0x48656c6c);
		//dataView.setInt
		console.log(dataView.getInt32(0).toString(16));
		//var arrbufPayload = new ArrayBuffer
		var msg = new Messaging.Message(buffer);
		console.log(msg.payloadBytes,msg.payloadString);
		*/
	});

});

	<|endoftext|>


<commit_before>$(document).ready(function () {

function update_product_image(event_source, product_id) {
    var $img = $(event_source).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img:first, img.product_detail_img');
    $img.attr("src", "/website/image/product.product/" + product_id + "/image");
    $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
        .data('oe-model', 'product.product').data('oe-id', product_id);
}

$('.oe_website_sale').each(function () {
    var oe_website_sale = this;

    var $shippingDifferent = $("select[name='shipping_id']", oe_website_sale);
    $shippingDifferent.change(function (event) {
        var value = +$shippingDifferent.val();
        var data = $shippingDifferent.find("option:selected").data();
        var $snipping = $(".js_shipping", oe_website_sale);
        var $inputs = $snipping.find("input");
        var $selects = $snipping.find("select");

        $snipping.toggle(!!value);
        $inputs.attr("readonly", value <= 0 ? null : "readonly" ).prop("readonly", value <= 0 ? null : "readonly" );
        $selects.attr("disabled", value <= 0 ? null : "disabled" ).prop("disabled", value <= 0 ? null : "disabled" );

        $inputs.each(function () {
            $(this).val( data[$(this).attr("name")] || "" );
        });
    });

    $(oe_website_sale).on("change", 'input[name="add_qty"]', function (event) {
        product_ids = [];
        var product_dom = $(".js_add_cart_variants[data-attribute_value_ids]").first();
        if (!product_dom.length) {
            return;
        }
        _.each(product_dom.data("attribute_value_ids"), function(entry) {
            product_ids.push(entry);});
        var qty = $(event.target).closest('form').find('input[name="add_qty"]').val();

        openerp.jsonRpc("/shop/get_unit_price", 'call', {'product_ids': product_ids,'add_qty': parseInt(qty)})
        .then(function (data) {
            var current = product_dom.data("attribute_value_ids");
            for(var j=0; j < current.length; j++){
                current[j][2] = data[current[j][0]];
            }
            product_dom.attr("data-attribute_value_ids", JSON.stringify(current)).trigger("change");
        });
    });

    // change for css
    $(oe_website_sale).on('mouseup touchend', '.js_publish', function (ev) {
        $(ev.currentTarget).parents(".thumbnail").toggleClass("disabled");
    });

    $(oe_website_sale).find(".oe_cart input.js_quantity").on("change", function () {
        var $input = $(this);
        if ($input.data('update_change')) {
            return;
        }
        var value = parseInt($input.val(), 10);
        var $dom = $(this).closest('tr');
        var default_price = parseFloat($dom.find('.text-danger > span.oe_currency_value').text());
        var $dom_optional = $dom.nextUntil(':not(.optional_product.info)');
        var line_id = parseInt($input.data('line-id'),10);
        var product_id = parseInt($input.data('product-id'),10);
        var product_ids = [product_id];
        if (isNaN(value)) value = 0;
        $dom_optional.each(function(){
            $(this).find('.js_quantity').text(value);
            product_ids.push($(this).find('span[data-product-id]').data('product-id'));
        });
        $input.data('update_change', true);
        openerp.jsonRpc("/shop/get_unit_price", 'call', {
            'product_ids': product_ids,
            'add_qty': value,
            'use_order_pricelist': true})
        .then(function (res) {
            //basic case
            $dom.find('span.oe_currency_value').last().text(res[product_id].toFixed(2));
            $dom.find('.text-danger').toggle(res[product_id]<default_price && (default_price-res[product_id] > default_price/100));
            //optional case
            $dom_optional.each(function(){
                var id = $(this).find('span[data-product-id]').data('product-id');
                var price = parseFloat($(this).find(".text-danger > span.oe_currency_value").text());
                $(this).find("span.oe_currency_value").last().text(res[id].toFixed(2));
                $(this).find('.text-danger').toggle(res[id]<price && (price-res[id]>price/100));
            });
            openerp.jsonRpc("/shop/cart/update_json", 'call', {
            'line_id': line_id,
            'product_id': parseInt($input.data('product-id'),10),
            'set_qty': value})
            .then(function (data) {
                $input.data('update_change', false);
                if (value !== parseInt($input.val(), 10)) {
                    $input.trigger('change');
                    return;
                }
                if (!data.quantity) {
                    location.reload(true);
                    return;
                }
                var $q = $(".my_cart_quantity");
                $q.parent().parent().removeClass("hidden", !data.quantity);
                $q.html(data.cart_quantity).hide().fadeIn(600);

                $input.val(data.quantity);
                $('.js_quantity[data-line-id='+line_id+']').val(data.quantity).html(data.quantity);
                $("#cart_total").replaceWith(data['website_sale.total']);
                if (data.warning) {
                    var cart_alert = $('.oe_cart').parent().find('#data_warning');
                    if (cart_alert.length == 0) {
                        $('.oe_cart').prepend('
'+
                                '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning + '
');
                    }
                    else {
                        cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning);
                    }
                    $input.val(data.quantity);
                }
            });
        });
    });

    // hack to add and rome from cart with json
    $(oe_website_sale).on('click', 'a.js_add_cart_json', function (ev) {
        ev.preventDefault();
        var $link = $(ev.currentTarget);
        var $input = $link.parent().find("input");
        var product_id = +$input.closest('div:has(input[name="product_id"])').find('input[name="product_id"]').val();
        var min = parseFloat($input.data("min") || 0);
        var max = parseFloat($input.data("max") || Infinity);
        var quantity = ($link.has(".fa-minus").length ? -1 : 1) + parseFloat($input.val(),10);
        // if they are more of one input for this product (eg: option modal)
        $('input[name="'+$input.attr("name")+'"]').add($input).filter(function () {
            var $prod = $(this).closest('*:has(input[name="product_id"])');
            return !$prod.length || +$prod.find('input[name="product_id"]').val() === product_id;
        }).val(quantity > min ? (quantity < max ? quantity : max) : min);
        $input.change();
        return false;
    });

    $('.oe_website_sale .a-submit, #comment .a-submit').off('click').on('click', function (event) {
        if (!event.isDefaultPrevented() && !$(this).is(".disabled")) {
            $(this).closest('form').submit();
        }
    });
    $('form.js_attributes input, form.js_attributes select', oe_website_sale).on('change', function () {
        $(this).closest("form").submit();
    });

    // change price when they are variants
    $('form.js_add_cart_json label', oe_website_sale).on('mouseup touchend', function (ev) {
        var $label = $(this);
        var $price = $label.parents("form:first").find(".oe_price .oe_currency_value");
        if (!$price.data("price")) {
            $price.data("price", parseFloat($price.text()));
        }
        var value = $price.data("price") + parseFloat($label.find(".badge span").text() || 0);
        var dec = value % 1;
        $price.html(value + (dec < 0.01 ? ".00" : (dec < 1 ? "0" : "") ));
    });
    // hightlight selected color
    $('.css_attribute_color input', oe_website_sale).on('change', function (ev) {
        $('.css_attribute_color').removeClass("active");
        $('.css_attribute_color:has(input:checked)').addClass("active");
    });

    function price_to_str(price) {
        price = Math.round(price * 100) / 100;
        var dec = Math.round((price % 1) * 100);
        return price + (dec ? '' : '.0') + (dec%10 ? '' : '0');
    }

    $(oe_website_sale).on('change', 'input.js_product_change', function (ev) {
        var $parent = $(this).closest('.js_product');
        $parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(this).data('lst_price')) );
        $parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(this).data('price')) );
        update_product_image(this, +$(this).val());
    });

    $(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change, ul[data-attribute_value_ids]', function (ev) {
        var $ul = $(ev.target).closest('.js_add_cart_variants');
        var $parent = $ul.closest('.js_product');
        var $product_id = $parent.find('input.product_id').first();
        var $price = $parent.find(".oe_price:first .oe_currency_value");
        var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
        var $optional_price = $parent.find(".oe_optional:first .oe_currency_value");
        var variant_ids = $ul.data("attribute_value_ids");
        var values = [];
        $parent.find('input.js_variant_change:checked, select.js_variant_change').each(function () {
            values.push(+$(this).val());
        });

        $parent.find("label").removeClass("text-muted css_not_available");

        var product_id = false;
        for (var k in variant_ids) {
            if (_.isEmpty(_.difference(variant_ids[k][1], values))) {
                $price.html(price_to_str(variant_ids[k][2]));
                $default_price.html(price_to_str(variant_ids[k][3]));
                if (variant_ids[k][3]-variant_ids[k][2]>0.2) {
                    $default_price.closest('.oe_website_sale').addClass("discount");
                    $optional_price.closest('.oe_optional').show().css('text-decoration', 'line-through');
                } else {
                    $default_price.closest('.oe_website_sale').removeClass("discount");
                    $optional_price.closest('.oe_optional').hide();
                }
                product_id = variant_ids[k][0];
                break;
            }
        }

        if (product_id) {
            update_product_image(this, product_id);
        }

        $parent.find("input.js_variant_change:radio, select.js_variant_change").each(function () {
            var $input = $(this);
            var id = +$input.val();
            var values = [id];

            $parent.find("ul:not(:has(input.js_variant_change[value='" + id + "'])) input.js_variant_change:checked, select").each(function () {
                values.push(+$(this).val());
            });

            for (var k in variant_ids) {
                if (!_.difference(values, variant_ids[k][1]).length) {
                    return;
                }
            }
            $input.closest("label").addClass("css_not_available");
            $input.find("option[value='" + id + "']").addClass("css_not_available");
        });

        if (product_id) {
            $parent.removeClass("css_not_available");
            $product_id.val(product_id);
            $parent.find("#add_to_cart").removeClass("disabled");
        } else {
            $parent.addClass("css_not_available");
            $product_id.val(0);
            $parent.find("#add_to_cart").addClass("disabled");
        }
    });

    $('div.js_product', oe_website_sale).each(function () {
        $('input.js_product_change', this).first().trigger('change');
    });

    $('.js_add_cart_variants', oe_website_sale).each(function () {
        $('input.js_variant_change, select.js_variant_change', this).first().trigger('change');
    });

    $(oe_website_sale).on('change', "select[name='country_id']", function () {
        var $select = $("select[name='state_id']");
        $select.find("option:not(:first)").hide();
        var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size();
        $select.parent().toggle(nb>1);
    });
    $(oe_website_sale).find("select[name='country_id']").change();

    $(oe_website_sale).on('change', "select[name='shipping_country_id']", function () {
        var $select = $("select[name='shipping_state_id']");
        $select.find("option:not(:first)").hide();
        var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size();
        $select.parent().toggle(nb>1);
    });
    $(oe_website_sale).find("select[name='shipping_country_id']").change();
});
});
<commit_msg>[IMP] website_sale: no change in behavior but allow other comportment for new ecommerce designs<commit_after>$(document).ready(function () {

function update_product_image(event_source, product_id) {
    var $img = $(event_source).closest('tr.js_product, .oe_website_sale').find('span[data-oe-model^="product."][data-oe-type="image"] img:first, img.product_detail_img');
    $img.attr("src", "/website/image/product.product/" + product_id + "/image");
    $img.parent().attr('data-oe-model', 'product.product').attr('data-oe-id', product_id)
        .data('oe-model', 'product.product').data('oe-id', product_id);
}

$('.oe_website_sale').each(function () {
    var oe_website_sale = this;

    var $shippingDifferent = $("select[name='shipping_id']", oe_website_sale);
    $shippingDifferent.change(function (event) {
        var value = +$shippingDifferent.val();
        var data = $shippingDifferent.find("option:selected").data();
        var $snipping = $(".js_shipping", oe_website_sale);
        var $inputs = $snipping.find("input");
        var $selects = $snipping.find("select");

        $snipping.toggle(!!value);
        $inputs.attr("readonly", value <= 0 ? null : "readonly" ).prop("readonly", value <= 0 ? null : "readonly" );
        $selects.attr("disabled", value <= 0 ? null : "disabled" ).prop("disabled", value <= 0 ? null : "disabled" );

        $inputs.each(function () {
            $(this).val( data[$(this).attr("name")] || "" );
        });
    });

    $(oe_website_sale).on("change", 'input[name="add_qty"]', function (event) {
        product_ids = [];
        var product_dom = $(".js_add_cart_variants[data-attribute_value_ids]").first();
        if (!product_dom.length) {
            return;
        }
        _.each(product_dom.data("attribute_value_ids"), function(entry) {
            product_ids.push(entry);});
        var qty = $(event.target).closest('form').find('input[name="add_qty"]').val();

        openerp.jsonRpc("/shop/get_unit_price", 'call', {'product_ids': product_ids,'add_qty': parseInt(qty)})
        .then(function (data) {
            var current = product_dom.data("attribute_value_ids");
            for(var j=0; j < current.length; j++){
                current[j][2] = data[current[j][0]];
            }
            product_dom.attr("data-attribute_value_ids", JSON.stringify(current)).trigger("change");
        });
    });

    // change for css
    $(oe_website_sale).on('mouseup touchend', '.js_publish', function (ev) {
        $(ev.currentTarget).parents(".thumbnail").toggleClass("disabled");
    });

    $(oe_website_sale).find("input.js_quantity[data-product-id]").on("change", function () {
        var $input = $(this);
        if ($input.data('update_change')) {
            return;
        }
        var value = parseInt($input.val(), 10);
        var $dom = $(this).closest('tr');
        var default_price = parseFloat($dom.find('.text-danger > span.oe_currency_value').text());
        var $dom_optional = $dom.nextUntil(':not(.optional_product.info)');
        var line_id = parseInt($input.data('line-id'),10);
        var product_id = parseInt($input.data('product-id'),10);
        var product_ids = [product_id];
        if (isNaN(value)) value = 0;
        $dom_optional.each(function(){
            $(this).find('.js_quantity').text(value);
            product_ids.push($(this).find('span[data-product-id]').data('product-id'));
        });
        $input.data('update_change', true);
        openerp.jsonRpc("/shop/get_unit_price", 'call', {
            'product_ids': product_ids,
            'add_qty': value,
            'use_order_pricelist': true})
        .then(function (res) {
            //basic case
            $dom.find('span.oe_currency_value').last().text(res[product_id].toFixed(2));
            $dom.find('.text-danger').toggle(res[product_id]<default_price && (default_price-res[product_id] > default_price/100));
            //optional case
            $dom_optional.each(function(){
                var id = $(this).find('span[data-product-id]').data('product-id');
                var price = parseFloat($(this).find(".text-danger > span.oe_currency_value").text());
                $(this).find("span.oe_currency_value").last().text(res[id].toFixed(2));
                $(this).find('.text-danger').toggle(res[id]<price && (price-res[id]>price/100));
            });
            openerp.jsonRpc("/shop/cart/update_json", 'call', {
            'line_id': line_id,
            'product_id': parseInt($input.data('product-id'),10),
            'set_qty': value})
            .then(function (data) {
                $input.data('update_change', false);
                if (value !== parseInt($input.val(), 10)) {
                    $input.trigger('change');
                    return;
                }
                if (!data.quantity) {
                    location.reload(true);
                    return;
                }
                var $q = $(".my_cart_quantity");
                $q.parent().parent().removeClass("hidden", !data.quantity);
                $q.html(data.cart_quantity).hide().fadeIn(600);

                $input.val(data.quantity);
                $('.js_quantity[data-line-id='+line_id+']').val(data.quantity).html(data.quantity);
                $("#cart_total").replaceWith(data['website_sale.total']);
                if (data.warning) {
                    var cart_alert = $('.oe_cart').parent().find('#data_warning');
                    if (cart_alert.length == 0) {
                        $('.oe_cart').prepend('
'+
                                '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning + '
');
                    }
                    else {
                        cart_alert.html('<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> ' + data.warning);
                    }
                    $input.val(data.quantity);
                }
            });
        });
    });

    // hack to add and rome from cart with json
    $(oe_website_sale).on('click', 'a.js_add_cart_json', function (ev) {
        ev.preventDefault();
        var $link = $(ev.currentTarget);
        var $input = $link.parent().find("input");
        var product_id = +$input.closest('*:has(input[name="product_id"])').find('input[name="product_id"]').val();
        var min = parseFloat($input.data("min") || 0);
        var max = parseFloat($input.data("max") || Infinity);
        var quantity = ($link.has(".fa-minus").length ? -1 : 1) + parseFloat($input.val(),10);
        // if they are more of one input for this product (eg: option modal)
        $('input[name="'+$input.attr("name")+'"]').add($input).filter(function () {
            var $prod = $(this).closest('*:has(input[name="product_id"])');
            return !$prod.length || +$prod.find('input[name="product_id"]').val() === product_id;
        }).val(quantity > min ? (quantity < max ? quantity : max) : min);
        $input.change();
        return false;
    });

    $('.oe_website_sale .a-submit, #comment .a-submit').off('click').on('click', function (event) {
        if (!event.isDefaultPrevented() && !$(this).is(".disabled")) {
            $(this).closest('form').submit();
        }
    });
    $('form.js_attributes input, form.js_attributes select', oe_website_sale).on('change', function () {
        $(this).closest("form").submit();
    });

    // change price when they are variants
    $('form.js_add_cart_json label', oe_website_sale).on('mouseup touchend', function (ev) {
        var $label = $(this);
        var $price = $label.parents("form:first").find(".oe_price .oe_currency_value");
        if (!$price.data("price")) {
            $price.data("price", parseFloat($price.text()));
        }
        var value = $price.data("price") + parseFloat($label.find(".badge span").text() || 0);
        var dec = value % 1;
        $price.html(value + (dec < 0.01 ? ".00" : (dec < 1 ? "0" : "") ));
    });
    // hightlight selected color
    $('.css_attribute_color input', oe_website_sale).on('change', function (ev) {
        $('.css_attribute_color').removeClass("active");
        $('.css_attribute_color:has(input:checked)').addClass("active");
    });

    function price_to_str(price) {
        price = Math.round(price * 100) / 100;
        var dec = Math.round((price % 1) * 100);
        return price + (dec ? '' : '.0') + (dec%10 ? '' : '0');
    }

    $(oe_website_sale).on('change', 'input.js_product_change', function (ev) {
        var $parent = $(this).closest('.js_product');
        $parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(this).data('lst_price')) );
        $parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(this).data('price')) );
        update_product_image(this, +$(this).val());
    });

    $(oe_website_sale).on('change', 'input.js_variant_change, select.js_variant_change, ul[data-attribute_value_ids]', function (ev) {
        var $ul = $(ev.target).closest('.js_add_cart_variants');
        var $parent = $ul.closest('.js_product');
        var $product_id = $parent.find('input.product_id').first();
        var $price = $parent.find(".oe_price:first .oe_currency_value");
        var $default_price = $parent.find(".oe_default_price:first .oe_currency_value");
        var $optional_price = $parent.find(".oe_optional:first .oe_currency_value");
        var variant_ids = $ul.data("attribute_value_ids");
        var values = [];
        $parent.find('input.js_variant_change:checked, select.js_variant_change').each(function () {
            values.push(+$(this).val());
        });

        $parent.find("label").removeClass("text-muted css_not_available");

        var product_id = false;
        for (var k in variant_ids) {
            if (_.isEmpty(_.difference(variant_ids[k][1], values))) {
                $price.html(price_to_str(variant_ids[k][2]));
                $default_price.html(price_to_str(variant_ids[k][3]));
                if (variant_ids[k][3]-variant_ids[k][2]>0.2) {
                    $default_price.closest('.oe_website_sale').addClass("discount");
                    $optional_price.closest('.oe_optional').show().css('text-decoration', 'line-through');
                } else {
                    $default_price.closest('.oe_website_sale').removeClass("discount");
                    $optional_price.closest('.oe_optional').hide();
                }
                product_id = variant_ids[k][0];
                break;
            }
        }

        if (product_id) {
            update_product_image(this, product_id);
        }

        $parent.find("input.js_variant_change:radio, select.js_variant_change").each(function () {
            var $input = $(this);
            var id = +$input.val();
            var values = [id];

            $parent.find("ul:not(:has(input.js_variant_change[value='" + id + "'])) input.js_variant_change:checked, select").each(function () {
                values.push(+$(this).val());
            });

            for (var k in variant_ids) {
                if (!_.difference(values, variant_ids[k][1]).length) {
                    return;
                }
            }
            $input.closest("label").addClass("css_not_available");
            $input.find("option[value='" + id + "']").addClass("css_not_available");
        });

        if (product_id) {
            $parent.removeClass("css_not_available");
            $product_id.val(product_id);
            $parent.find("#add_to_cart").removeClass("disabled");
        } else {
            $parent.addClass("css_not_available");
            $product_id.val(0);
            $parent.find("#add_to_cart").addClass("disabled");
        }
    });

    $('div.js_product', oe_website_sale).each(function () {
        $('input.js_product_change', this).first().trigger('change');
    });

    $('.js_add_cart_variants', oe_website_sale).each(function () {
        $('input.js_variant_change, select.js_variant_change', this).first().trigger('change');
    });

    $(oe_website_sale).on('change', "select[name='country_id']", function () {
        var $select = $("select[name='state_id']");
        $select.find("option:not(:first)").hide();
        var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size();
        $select.parent().toggle(nb>1);
    });
    $(oe_website_sale).find("select[name='country_id']").change();

    $(oe_website_sale).on('change', "select[name='shipping_country_id']", function () {
        var $select = $("select[name='shipping_state_id']");
        $select.find("option:not(:first)").hide();
        var nb = $select.find("option[data-country_id="+($(this).val() || 0)+"]").show().size();
        $select.parent().toggle(nb>1);
    });
    $(oe_website_sale).find("select[name='shipping_country_id']").change();
});
});
<|endoftext|>