<commit_before>'use strict';

/* Services */

angular.module('myApp.services', []).

factory("flash", function($rootScope) {
  var queue = [];
  var currentMessage = "";

  $rootScope.$on("$routeChangeSuccess", function() {
    currentMessage = queue.shift() || "";
  });

  return {
    setMessage: function(message) {
      queue.push(message);
    },
    getMessage: function() {
      return currentMessage;
    }
  };
}).

  value('version', '0.1').

  service('EventBus', function() {
    var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
    return eb;
  }).

  service('AuthService', [function() {
    this.getPerson = function() {
      return {
        firstname: "(Walle)",
        lastname: "(Web)",
        email: "ww@www.org"
      };
    }
  }]).

  service('AnmalanService', ['AuthService', function(authService) {
    this.addLogMessage = function(_id, _subject, _body, _user, fnDone) {
      var promise = $.Deferred();
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
        eb.onopen = function() {
            eb.send('skapa.loggmeddelande', {id: _id, username: _user, subject: _subject, body: _body},
            function(reply) {
              if (reply.status == "ok") {
                promise.resolve(reply);
            } else {
              promise.reject(reply);
            }
            });
      };
      return promise;
    };

    this.skickaTillPolisen = function(_id, _subject, _body, _user, fnDone) {
      var promise = $.Deferred();
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      eb.onopen = function() {
        eb.send('skicka.till.polisen', {id: _id, username: _user, subject: _subject, body: _body},
        function(reply) {
          if (reply.status == "ok") {
            promise.resolve(reply);
          } else {
            promise.reject(reply);
          }
        });
       };
       return promise;
    };

    this.save = function(_anmalan) {
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      var promise = $.Deferred();
      eb.onopen = function() {
        eb.send('skapa.anmalan', {skapadAv: authService.getPerson(), anmalan: _anmalan},
        function(reply) {
          if (reply.status == "ok") {
            promise.resolve(reply._id);
          } else {
            promise.reject(reply);
          }
          console.log('AnmalanService::save processing reply', reply);
          eb.close();
        });
      };
      return promise;
    };

    this.addFile = function(_id, _file, _user, fnDone) {
      //https://github.com/vert-x/vertx-examples/tree/master/src/raw/java/upload
      //UploadClient
      //console.log('myfile : '+_file);
      console.log('myfile : '+_file.files[0].name);

      var fd = new FormData();
      fd.append("uploadedFile", _file.files[0]);

      //Göra lite snyggare sen
      var uploadComplete = function(evt) {
        console.log(evt.target.responseText);
      };
      var uploadFailed = function(evt) {
        console.log("There was an error attempting to upload the file.");
      };
      var uploadCanceled = function(evt) {
        console.log("The upload has been canceled by the user or the browser dropped the connection.");
      };

      var xhr = new XMLHttpRequest();
      //xhr.upload.addEventListener("progress", _uploadProgress, false);
      xhr.addEventListener("load", uploadComplete, false);
      xhr.addEventListener("error", uploadFailed, false);
      xhr.addEventListener("abort", uploadCanceled, false);
      xhr.open("POST", "http://localhost:8081/form");
      xhr.send(fd);
      console.log('myfile sent!');
    };

    this.findOne = function(id, _user, fnOpen) {
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      eb.onopen = function() {
        eb.send('test.mongodb', {'action': 'find', 'collection': 'anmalningar', matcher: {'_id': id + ""}},
        function(reply) {
          console.log('AnmalanService::findOne processing reply', reply);
          fnOpen.call(this, "ok", reply);
          eb.close();
        });
      };
    };

    this.findAll = function(fn, fnUpdated) {
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      eb.onopen = function() {
        console.log("Buss open");
        eb.send('test.mongodb', {action: 'find', collection: 'anmalningar', matcher: {} },
          function(reply) {
            console.log('AnmalanService::processing reply', reply);
            if (reply.status === 'ok') {
              var anmalanArray = [];
              for (var i = 0; i < reply.results.length; i++) {
                anmalanArray[i] = reply.results[i];
              }
              fn.call(this, "ok", anmalanArray);
            } else {
              console.error('Failed to retrieve tickets: ' + reply.message);
              fn.call("error", null);
            }
          }
        );
        eb.registerHandler('anmalan.uppdaterad',
          function(updatedEvent) {
            console.log('AnmalanService::findAll anmalan.uppdaterad', updatedEvent);
            fnUpdated.call(this, "ok", updatedEvent);
          }
        );
      };
      console.log("Events are set up.");
      }
    }]).

    service('global', function($cookieStore, $location, $filter) {
      var globalService = {};
      globalService.user = null;
      globalService.isAuth = function (){
        if (globalService.user == null) {
          globalService.user = $cookieStore.get('user');
        }
        return (globalService.user != null);
      };
      globalService.setUser = function(newUser) {
        globalService.user = newUser;
        if (globalService.user == null)
          $cookieStore.remove('user');
        else
          $cookieStore.put('user', globalService.user);
      };
      globalService.getUser = function() {
        return globalService.user;
      };
      return globalService;
    }).

    service('TimeDisplayService', [function() {
      this.timeSince = function(date) {
        var seconds = Math.floor((new Date() - date) / 1000);
        var interval = Math.floor(seconds / 31536000);

        if (interval > 1) {
          return interval + " år";
        }
        interval = Math.floor(seconds / 2592000);
        if (interval > 1) {
          return interval + " månader";
        }
        interval = Math.floor(seconds / 86400);
        if (interval == 1) {
          return "en dag";
        } else if (interval > 1) {
          return interval + " dagar";
        }
        interval = Math.floor(seconds / 3600);
        if (interval == 1) {
          return "en timme";
        } else if (interval > 1) {
          return interval + " timmar";
        }
        interval = Math.floor(seconds / 60);
        if (interval == 1) {
          return "en minut";
        } else if (interval > 1) {
          return interval + " minuter";
        }
        var seconds = Math.floor(seconds);
        if (seconds == 1) {
          return "en sekund";
        } else if (seconds == 0) {
          return null;
        } else {
          return seconds + " sekunder";
        }
      }
    }]).

    service('LoginService', ['EventBus', function(eb) {
      this.login = function(username, password) {
      var promise = $.Deferred();
      eb.login(username, password,
        function (reply) {
          if (reply.status === 'ok') {
            promise.resolve();
          } else {
            promise.reject();
          }
        });
      return promise;
      }
    }
  ]);
<commit_msg>Skicka med skapadAv till skapa.loggmeddelande.<commit_after>'use strict';

/* Services */

angular.module('myApp.services', []).

factory("flash", function($rootScope) {
  var queue = [];
  var currentMessage = "";

  $rootScope.$on("$routeChangeSuccess", function() {
    currentMessage = queue.shift() || "";
  });

  return {
    setMessage: function(message) {
      queue.push(message);
    },
    getMessage: function() {
      return currentMessage;
    }
  };
}).

  value('version', '0.1').

  service('EventBus', function() {
    var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
    return eb;
  }).

  service('AuthService', [function() {
    this.getPerson = function(username) {
      username = username || "(Walle)";
      return {
        firstname: username,
        lastname: "(Web)",
        email: "ww@www.org"
      };
    }
  }]).

  service('AnmalanService', ['AuthService', function(authService) {
    this.addLogMessage = function(_id, _subject, _body, _user, fnDone) {
      var promise = $.Deferred();
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
        eb.onopen = function() {
            eb.send('skapa.loggmeddelande', {id: _id, skapadAv: authService.getPerson(_user), subject: _subject, body: _body},
            function(reply) {
              if (reply.status == "ok") {
                promise.resolve(reply);
            } else {
              promise.reject(reply);
            }
            });
      };
      return promise;
    };

    this.skickaTillPolisen = function(_id, _subject, _body, _user, fnDone) {
      var promise = $.Deferred();
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      eb.onopen = function() {
        eb.send('skicka.till.polisen', {id: _id, username: _user, subject: _subject, body: _body},
        function(reply) {
          if (reply.status == "ok") {
            promise.resolve(reply);
          } else {
            promise.reject(reply);
          }
        });
       };
       return promise;
    };

    this.save = function(_anmalan) {
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      var promise = $.Deferred();
      eb.onopen = function() {
        eb.send('skapa.anmalan', {skapadAv: authService.getPerson(), anmalan: _anmalan},
        function(reply) {
          if (reply.status == "ok") {
            promise.resolve(reply._id);
          } else {
            promise.reject(reply);
          }
          console.log('AnmalanService::save processing reply', reply);
          eb.close();
        });
      };
      return promise;
    };

    this.addFile = function(_id, _file, _user, fnDone) {
      //https://github.com/vert-x/vertx-examples/tree/master/src/raw/java/upload
      //UploadClient
      //console.log('myfile : '+_file);
      console.log('myfile : '+_file.files[0].name);

      var fd = new FormData();
      fd.append("uploadedFile", _file.files[0]);

      //Göra lite snyggare sen
      var uploadComplete = function(evt) {
        console.log(evt.target.responseText);
      };
      var uploadFailed = function(evt) {
        console.log("There was an error attempting to upload the file.");
      };
      var uploadCanceled = function(evt) {
        console.log("The upload has been canceled by the user or the browser dropped the connection.");
      };

      var xhr = new XMLHttpRequest();
      //xhr.upload.addEventListener("progress", _uploadProgress, false);
      xhr.addEventListener("load", uploadComplete, false);
      xhr.addEventListener("error", uploadFailed, false);
      xhr.addEventListener("abort", uploadCanceled, false);
      xhr.open("POST", "http://localhost:8081/form");
      xhr.send(fd);
      console.log('myfile sent!');
    };

    this.findOne = function(id, _user, fnOpen) {
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      eb.onopen = function() {
        eb.send('test.mongodb', {'action': 'find', 'collection': 'anmalningar', matcher: {'_id': id + ""}},
        function(reply) {
          console.log('AnmalanService::findOne processing reply', reply);
          fnOpen.call(this, "ok", reply);
          eb.close();
        });
      };
    };

    this.findAll = function(fn, fnUpdated) {
      var eb = new vertx.EventBus(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/eventbus');
      eb.onopen = function() {
        console.log("Buss open");
        eb.send('test.mongodb', {action: 'find', collection: 'anmalningar', matcher: {} },
          function(reply) {
            console.log('AnmalanService::processing reply', reply);
            if (reply.status === 'ok') {
              var anmalanArray = [];
              for (var i = 0; i < reply.results.length; i++) {
                anmalanArray[i] = reply.results[i];
              }
              fn.call(this, "ok", anmalanArray);
            } else {
              console.error('Failed to retrieve tickets: ' + reply.message);
              fn.call("error", null);
            }
          }
        );
        eb.registerHandler('anmalan.uppdaterad',
          function(updatedEvent) {
            console.log('AnmalanService::findAll anmalan.uppdaterad', updatedEvent);
            fnUpdated.call(this, "ok", updatedEvent);
          }
        );
      };
      console.log("Events are set up.");
      }
    }]).

    service('global', function($cookieStore, $location, $filter) {
      var globalService = {};
      globalService.user = null;
      globalService.isAuth = function (){
        if (globalService.user == null) {
          globalService.user = $cookieStore.get('user');
        }
        return (globalService.user != null);
      };
      globalService.setUser = function(newUser) {
        globalService.user = newUser;
        if (globalService.user == null)
          $cookieStore.remove('user');
        else
          $cookieStore.put('user', globalService.user);
      };
      globalService.getUser = function() {
        return globalService.user;
      };
      return globalService;
    }).

    service('TimeDisplayService', [function() {
      this.timeSince = function(date) {
        var seconds = Math.floor((new Date() - date) / 1000);
        var interval = Math.floor(seconds / 31536000);

        if (interval > 1) {
          return interval + " år";
        }
        interval = Math.floor(seconds / 2592000);
        if (interval > 1) {
          return interval + " månader";
        }
        interval = Math.floor(seconds / 86400);
        if (interval == 1) {
          return "en dag";
        } else if (interval > 1) {
          return interval + " dagar";
        }
        interval = Math.floor(seconds / 3600);
        if (interval == 1) {
          return "en timme";
        } else if (interval > 1) {
          return interval + " timmar";
        }
        interval = Math.floor(seconds / 60);
        if (interval == 1) {
          return "en minut";
        } else if (interval > 1) {
          return interval + " minuter";
        }
        var seconds = Math.floor(seconds);
        if (seconds == 1) {
          return "en sekund";
        } else if (seconds == 0) {
          return null;
        } else {
          return seconds + " sekunder";
        }
      }
    }]).

    service('LoginService', ['EventBus', function(eb) {
      this.login = function(username, password) {
      var promise = $.Deferred();
      eb.login(username, password,
        function (reply) {
          if (reply.status === 'ok') {
            promise.resolve();
          } else {
            promise.reject();
          }
        });
      return promise;
      }
    }
  ]);
<|endoftext|>


<commit_before>/* eslint-env mocha */
import React from 'react';
import {mount, shallow} from 'enzyme';
import {match, spy} from 'sinon';
import {assert} from 'chai';
import Menu from './Menu';
import MenuItem from '../MenuItem';
import Divider from '../Divider';
import getMuiTheme from '../styles/getMuiTheme';
import keycode from 'keycode';

describe('<Menu />', () => {
  const muiTheme = getMuiTheme();
  const shallowWithContext = (node) => shallow(node, {context: {muiTheme}});
  const mountWithContext = (node) => mount(node, {context: {muiTheme}});
  const keycodeEvent = (key) => ({keyCode: keycode(key)});

  describe('onMenuItemFocusChange', () => {
    function createMenu(props) {
      return (
        <Menu {...props}>
          <MenuItem primaryText="item 1" />
          <Divider />
          <MenuItem primaryText="item 2" />
          <MenuItem primaryText="item 3" />
        </Menu>
      );
    }

    it('is invoked when using the arrow key to go down to the bottom and back up to the top', () => {
      const onMenuItemFocusChangeSpy = spy();
      const menu = createMenu({
        disableAutoFocus: false,
        onMenuItemFocusChange: onMenuItemFocusChangeSpy,
      });
      const wrapper = mountWithContext(menu);

      assert(onMenuItemFocusChangeSpy.calledWith(null, 0),
             'initial focus should invoke callback with 0');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('down'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 1),
             'down-arrow invokes callback with index 1');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('down'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 2),
             'down-arrow invokes callback with index 2');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('down'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 2),
             'down-arrow at end invokes callback with unchanged index');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('up'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 1),
             'up-arrow invokes callback with 1');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('up'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 0),
             'up-arrow invokes callback with 0');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('up'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 0),
             'up-arrow at top invokes callback with unchanged index');
      onMenuItemFocusChangeSpy.reset();

      wrapper.unmount(); // Otherwise the timer in FocusRipple keeps Node from exiting
    });

    it('is invoked when props change', () => {
      const onMenuItemFocusChangeSpy = spy();
      const menu = createMenu({
        disableAutoFocus: true,
        onMenuItemFocusChange: onMenuItemFocusChangeSpy,
      });
      const wrapper = mountWithContext(menu);
      assert(onMenuItemFocusChangeSpy.notCalled,
             'should not be called when creating with disableAutoFocus=true');
      onMenuItemFocusChangeSpy.reset();

      wrapper.setProps({disableAutoFocus: false});
      assert(onMenuItemFocusChangeSpy.calledWith(null, 0),
             'changing disableAutoFocus to false invokes callback');
      onMenuItemFocusChangeSpy.reset();

      wrapper.setProps({disableAutoFocus: true});
      assert(onMenuItemFocusChangeSpy.calledWith(null, -1),
             'changing disableAutoFocus to true invokes callback');
      onMenuItemFocusChangeSpy.reset();

      wrapper.unmount(); // Otherwise the timer in FocusRipple keeps Node from exiting
    });

    it('is invoked for hotkeys', () => {
      const onMenuItemFocusChangeSpy = spy();
      const props = {
        disableAutoFocus: false,
        onMenuItemFocusChange: onMenuItemFocusChangeSpy,
      };
      const menu = (
        <Menu {...props}>
          <MenuItem primaryText="a00" />
          <MenuItem primaryText="b11" />
          <Divider />
          <MenuItem primaryText="b00" />
        </Menu>
      );
      const wrapper = mountWithContext(menu);

      wrapper.simulate('keydown', keycodeEvent('b'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 1),
             '"b" invokes callback with focus index 1');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('0'));
      // The Divider is incorrectly counted by Menu.setFocusIndexStartsWith().
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 3),
             '"b0" invokes callback with focus index 3, which is probably a bug');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('0'));
      assert(onMenuItemFocusChangeSpy.calledWith(match.object, 3),
             '"b0" invokes callback with focus index 3');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('!'));
      // It seems like the focus index should be changed to -1 here.
      assert(onMenuItemFocusChangeSpy.notCalled,
             '"b00!" does not change the focus index, which is probably a bug');
      onMenuItemFocusChangeSpy.reset();

      wrapper.unmount(); // Otherwise the timer in FocusRipple keeps Node from exiting
    });
  });

  it('should render MenuItem and Divider children', () => {
    const wrapper = shallowWithContext(
      <Menu>
        <MenuItem primaryText="item 1" />
        <Divider />
        <MenuItem primaryText="item 2" />
      </Menu>
    );

    const menuItemsAndDividers = wrapper.children().children().children();
    assert.strictEqual(menuItemsAndDividers.length, 3, 'there should be three children');
    assert.strictEqual(menuItemsAndDividers.get(0).type, MenuItem, 'first child should be a MenuItem');
    assert.strictEqual(menuItemsAndDividers.get(1).type, Divider, 'second child should be a Divider');
    assert.strictEqual(menuItemsAndDividers.get(2).type, MenuItem, 'third child should be a MenuItem');
    assert.deepEqual(
      menuItemsAndDividers.get(1).props.style,
      {
        marginTop: 7,
        marginBottom: 8,
      },
      'the Divider gets default styles'
    );
  });

  it("should merge the Divider's styles over the Menu's default divider styles", () => {
    const style = {
      color: 'red',
      marginTop: '999px',
    };
    const wrapper = shallowWithContext(
      <Menu>
        <Divider style={style} />
      </Menu>
    );

    const divider = wrapper.find(Divider);
    assert.strictEqual(divider.length, 1, 'there should be one divider child');

    assert.deepEqual(
      divider.props().style,
      Object.assign({}, style, {
        marginBottom: 8,
      }),
      "existing styles should be merged over Menu's styles"
    );
  });
});
<commit_msg>[Menu] Use simpler assert API<commit_after>/* eslint-env mocha */
import React from 'react';
import {mount, shallow} from 'enzyme';
import {spy} from 'sinon';
import {assert} from 'chai';
import Menu from './Menu';
import MenuItem from '../MenuItem';
import Divider from '../Divider';
import getMuiTheme from '../styles/getMuiTheme';
import keycode from 'keycode';

describe('<Menu />', () => {
  const muiTheme = getMuiTheme();
  const shallowWithContext = (node) => shallow(node, {context: {muiTheme}});
  const mountWithContext = (node) => mount(node, {context: {muiTheme}});
  const keycodeEvent = (key) => ({keyCode: keycode(key)});

  describe('onMenuItemFocusChange', () => {
    function createMenu(props) {
      return (
        <Menu {...props}>
          <MenuItem primaryText="item 1" />
          <Divider />
          <MenuItem primaryText="item 2" />
          <MenuItem primaryText="item 3" />
        </Menu>
      );
    }

    it('is invoked when using the arrow key to go down to the bottom and back up to the top', () => {
      const onMenuItemFocusChangeSpy = spy();
      const menu = createMenu({
        disableAutoFocus: false,
        onMenuItemFocusChange: onMenuItemFocusChangeSpy,
      });
      const wrapper = mountWithContext(menu);

      assert.deepEqual(onMenuItemFocusChangeSpy.args[0], [null, 0],
        'initial focus should invoke callback with 0');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('down'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 1,
        'down-arrow invokes callback with index 1');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('down'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 2,
        'down-arrow invokes callback with index 2');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('down'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 2,
        'down-arrow at end invokes callback with unchanged index');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('up'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 1,
        'up-arrow invokes callback with 1');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('up'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 0,
        'up-arrow invokes callback with 0');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('up'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 0,
        'up-arrow at top invokes callback with unchanged index');
      onMenuItemFocusChangeSpy.reset();

      wrapper.unmount(); // Otherwise the timer in FocusRipple keeps Node from exiting
    });

    it('is invoked when props change', () => {
      const onMenuItemFocusChangeSpy = spy();
      const menu = createMenu({
        disableAutoFocus: true,
        onMenuItemFocusChange: onMenuItemFocusChangeSpy,
      });
      const wrapper = mountWithContext(menu);
      assert.strictEqual(onMenuItemFocusChangeSpy.callCount, 0,
        'should not be called when creating with disableAutoFocus=true');
      onMenuItemFocusChangeSpy.reset();

      wrapper.setProps({disableAutoFocus: false});
      assert.deepEqual(onMenuItemFocusChangeSpy.args[0], [null, 0],
        'changing disableAutoFocus to false invokes callback');
      onMenuItemFocusChangeSpy.reset();

      wrapper.setProps({disableAutoFocus: true});
      assert.deepEqual(onMenuItemFocusChangeSpy.args[0], [null, -1],
        'changing disableAutoFocus to true invokes callback');
      onMenuItemFocusChangeSpy.reset();

      wrapper.unmount(); // Otherwise the timer in FocusRipple keeps Node from exiting
    });

    it('is invoked for hotkeys', () => {
      const onMenuItemFocusChangeSpy = spy();
      const menu = (
        <Menu
          disableAutoFocus={false}
          onMenuItemFocusChange={onMenuItemFocusChangeSpy}
        >
          <MenuItem primaryText="a00" />
          <MenuItem primaryText="b11" />
          <Divider />
          <MenuItem primaryText="b00" />
        </Menu>
      );
      const wrapper = mountWithContext(menu);

      wrapper.simulate('keydown', keycodeEvent('b'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 0,
        '"b" invokes callback with focus index 0');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('0'));
      // The Divider is incorrectly counted by Menu.setFocusIndexStartsWith().
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 3,
        '"b0" invokes callback with focus index 3, which is probably a bug');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('0'));
      assert.strictEqual(onMenuItemFocusChangeSpy.args[0][1], 3,
        '"b0" invokes callback with focus index 3');
      onMenuItemFocusChangeSpy.reset();

      wrapper.simulate('keydown', keycodeEvent('!'));
      // It seems like the focus index should be changed to -1 here.
      assert.strictEqual(onMenuItemFocusChangeSpy.callCount, 0,
        '"b00!" does not change the focus index, which is probably a bug');
      onMenuItemFocusChangeSpy.reset();

      wrapper.unmount(); // Otherwise the timer in FocusRipple keeps Node from exiting
    });
  });

  it('should render MenuItem and Divider children', () => {
    const wrapper = shallowWithContext(
      <Menu>
        <MenuItem primaryText="item 1" />
        <Divider />
        <MenuItem primaryText="item 2" />
      </Menu>
    );

    const menuItemsAndDividers = wrapper.children().children().children();
    assert.strictEqual(menuItemsAndDividers.length, 3, 'there should be three children');
    assert.strictEqual(menuItemsAndDividers.get(0).type, MenuItem, 'first child should be a MenuItem');
    assert.strictEqual(menuItemsAndDividers.get(1).type, Divider, 'second child should be a Divider');
    assert.strictEqual(menuItemsAndDividers.get(2).type, MenuItem, 'third child should be a MenuItem');
    assert.deepEqual(
      menuItemsAndDividers.get(1).props.style,
      {
        marginTop: 7,
        marginBottom: 8,
      },
      'the Divider gets default styles'
    );
  });

  it("should merge the Divider's styles over the Menu's default divider styles", () => {
    const style = {
      color: 'red',
      marginTop: '999px',
    };
    const wrapper = shallowWithContext(
      <Menu>
        <Divider style={style} />
      </Menu>
    );

    const divider = wrapper.find(Divider);
    assert.strictEqual(divider.length, 1, 'there should be one divider child');

    assert.deepEqual(
      divider.props().style,
      Object.assign({}, style, {
        marginBottom: 8,
      }),
      "existing styles should be merged over Menu's styles"
    );
  });
});
<|endoftext|>


<commit_before>({
    tearDown: function() {
        $A.storageService.getStorage('actions').remove('aura://ComponentController/ACTION$getApplication:{"chainLoadLabels":true,"name":"auraStorageTest:applicationTest"}');
    },

    testApplicationRefreshedEvent: {
        test: [
            function loadIframe(cmp) {
                $A.test.setTestTimeout(100000);
                cmp._frameLoaded = false;
                cmp._expected = "expected value";
                var frame = document.createElement("iframe");
                frame.src = "/auraStorageTest/applicationTest.app";
                frame.scrolling = "auto";
                frame.id = "myFrame";
                $A.util.on(frame, "load", function () {
                    cmp._frameLoaded = true;
                });
                var content = cmp.find("iframeContainer");
                $A.util.insertFirst(frame, content.getElement());

                this.waitForIframeLoad(cmp);
            },
            function insertStaleApplicationAction() {
                var iframeCmp = document.getElementById("myFrame").contentWindow.$A.getRoot();
                iframeCmp.addToStorage();
                $A.test.addWaitFor(true, function() {
                    return $A.util.getText(iframeCmp.find("status").getElement()) !== "Adding";
                }, function() {
                    $A.test.assertEquals("Done Adding", $A.util.getText(iframeCmp.find("status").getElement()));
                });
            },
            function reloadIframe(cmp) {
                cmp._frameLoaded = false;
                document.getElementById("myFrame").contentWindow.location.reload();
                this.waitForIframeLoad(cmp);
            },
            function verifyApplicationRefreshed(cmp) {
                var iframeCmp = document.getElementById("myFrame").contentWindow.$A.getRoot();
                $A.test.addWaitFor("YES", function() {
                    return iframeCmp.get('v.refreshed');
                });
            }
        ]
    },

    waitForIframeLoad: function(cmp) {
        var iframeWindow = document.getElementById("myFrame").contentWindow;
        $A.test.addWaitFor(true, function() {
            return cmp._frameLoaded
                && iframeWindow.$A
                && iframeWindow.$A.getRoot() !== undefined
                && !$A.test.isActionPending()
        });
    }
})
<commit_msg>Add @Flapper annotation to rerun flappy tests<commit_after>({
    tearDown: function() {
        $A.storageService.getStorage('actions').remove('aura://ComponentController/ACTION$getApplication:{"chainLoadLabels":true,"name":"auraStorageTest:applicationTest"}');
    },

    testApplicationRefreshedEvent: {
    	// TODO(W-2701964): Flapping in autobuilds, needs to be revisited
    	labels: ["flapper"],
        test: [
            function loadIframe(cmp) {
                $A.test.setTestTimeout(100000);
                cmp._frameLoaded = false;
                cmp._expected = "expected value";
                var frame = document.createElement("iframe");
                frame.src = "/auraStorageTest/applicationTest.app";
                frame.scrolling = "auto";
                frame.id = "myFrame";
                $A.util.on(frame, "load", function () {
                    cmp._frameLoaded = true;
                });
                var content = cmp.find("iframeContainer");
                $A.util.insertFirst(frame, content.getElement());

                this.waitForIframeLoad(cmp);
            },
            function insertStaleApplicationAction() {
                var iframeCmp = document.getElementById("myFrame").contentWindow.$A.getRoot();
                iframeCmp.addToStorage();
                $A.test.addWaitFor(true, function() {
                    return $A.util.getText(iframeCmp.find("status").getElement()) !== "Adding";
                }, function() {
                    $A.test.assertEquals("Done Adding", $A.util.getText(iframeCmp.find("status").getElement()));
                });
            },
            function reloadIframe(cmp) {
                cmp._frameLoaded = false;
                document.getElementById("myFrame").contentWindow.location.reload();
                this.waitForIframeLoad(cmp);
            },
            function verifyApplicationRefreshed(cmp) {
                var iframeCmp = document.getElementById("myFrame").contentWindow.$A.getRoot();
                $A.test.addWaitFor("YES", function() {
                    return iframeCmp.get('v.refreshed');
                });
            }
        ]
    },

    waitForIframeLoad: function(cmp) {
        var iframeWindow = document.getElementById("myFrame").contentWindow;
        $A.test.addWaitFor(true, function() {
            return cmp._frameLoaded
                && iframeWindow.$A
                && iframeWindow.$A.getRoot() !== undefined
                && !$A.test.isActionPending()
        });
    }
})
<|endoftext|>


<commit_before>
var _Deserializer = (function () {
    /**
     * @param {boolean} isEditor - if false, property with Fire.EditorOnly will be discarded
     */
    function _Deserializer(jsonObj, result, isEditor, classFinder) {
        this._editor = isEditor;
        this._classFinder = classFinder;

        this._idList = [];
        this._idObjList = [];
        this._idPropList = [];
        this.result = result || new Fire._DeserializeInfo();

        if (Array.isArray(jsonObj)) {
            var jsonList = jsonObj;
            var refCount = jsonList.length;
            this.deserializedList = new Array(refCount);
            // deserialize
            for (var i = 0; i < refCount; i++) {
                if (jsonList[i]) {
                    this.deserializedList[i] = _deserializeObject(this, jsonList[i]);
                }
            }
            this.deserializedData = refCount > 0 ? this.deserializedList[0] : [];

            //// callback
            //for (var j = 0; j < refCount; j++) {
            //    if (referencedList[j].onAfterDeserialize) {
            //        referencedList[j].onAfterDeserialize();
            //    }
            //}
        }
        else {
            this.deserializedList = new Array(1);
            this.deserializedData = jsonObj ? _deserializeObject(this, jsonObj) : null;
            this.deserializedList[0] = this.deserializedData;

            //// callback
            //if (deserializedData.onAfterDeserialize) {
            //    deserializedData.onAfterDeserialize();
            //}
        }

        // dereference
        _dereference(this);
    }

    var _dereference = function (self) {
        // 这里不采用遍历反序列化结果的方式，因为反序列化的结果如果引用到复杂的外部库，很容易堆栈溢出。
        var deserializedList = self.deserializedList;
        for (var i = 0, len = self._idList.length; i < len; i++) {
            var propName = self._idPropList[i];
            var id = self._idList[i];
            self._idObjList[i][propName] = deserializedList[id];
        }
    };

    function _deserializeObjField (self, obj, jsonObj, propName) {
        var id = jsonObj.__id__;
        if (typeof id === 'undefined') {
            var uuid = jsonObj.__uuid__;
            if (uuid) {
                self.result.uuidList.push(uuid);
                self.result.uuidObjList.push(obj);
                self.result.uuidPropList.push(propName);
            }
            else {
                obj[propName] = _deserializeObject(self, jsonObj);
            }
        }
        else {
            var dObj = self.deserializedList[id];
            if (dObj) {
                obj[propName] = dObj;
            }
            else {
                self._idList.push(id);
                self._idObjList.push(obj);
                self._idPropList.push(propName);
            }
        }
    }

    function _deserializePrimitiveObject (self, instance, serialized) {
        for (var propName in instance) {    // 遍历 instance，如果具有类型，才不会把 __type__ 也读进来
            var prop = serialized[propName];
            if (typeof prop !== 'undefined' && serialized.hasOwnProperty(propName)) {
                if (typeof prop !== 'object') {
                    instance[propName] = prop;
                }
                else {
                    if (prop) {
                        if ( !prop.__uuid__ && typeof prop.__id__ === 'undefined' ) {
                            instance[propName] = _deserializeObject(self, prop);
                        }
                        else {
                            _deserializeObjField(self, instance, prop, propName);
                        }
                    }
                    else {
                        instance[propName] = null;
                    }
                }
            }
        }
    }

    /**
     * @param {Object} serialized - The obj to deserialize, must be non-nil
     */
    var _deserializeObject = function (self, serialized) {
        var propName, prop;
        var obj = null;
        var klass = null;
        if (serialized.__type__) {
            klass = self._classFinder(serialized.__type__);
            if (!klass) {
                Fire.error('[Fire.deserialize] unknown type: ' + serialized.__type__);
                return null;
            }
            // instantiate a new object
            obj = new klass();
        }
        else if (!Array.isArray(serialized)) {
            // embedded primitive javascript object
            obj = serialized;
            //// jshint -W010
            //obj = new Object();
            //// jshint +W010
        }
        else {
            // array
            obj = serialized;
            for (var i = 0; i < serialized.length; i++) {
                prop = serialized[i];
                if (typeof prop === 'object' && prop) {
                    if (!prop.__uuid__ && typeof prop.__id__ === 'undefined') {
                        obj[i] = _deserializeObject(self, prop);
                    }
                    else {
                        _deserializeObjField(self, obj, prop, '' + i);
                    }
                }
            }
            return serialized;
        }

        // parse property
        if (klass && Fire._isFireClass(klass)) {
            var props = klass.__props__;
            if (!props) {
                return obj;
            }
            for (var p = 0; p < props.length; p++) {
                propName = props[p];
                var attrs = Fire.attr(klass, propName);
                // assume all prop in __props__ must have attr
                var hostType = attrs.hostType;
                if (!hostType) {
                    if (attrs.serializable === false) {
                        continue;   // skip nonSerialized
                    }
                    if (!self._editor && attrs.editorOnly) {
                        continue;   // skip editor only if not editor
                    }
                    prop = serialized[propName];
                    if (typeof prop !== 'undefined') {
                        if (typeof prop !== 'object') {
                            obj[propName] = prop;
                        }
                        else {
                            if (prop) {
                                if ( !prop.__uuid__ && typeof prop.__id__ === 'undefined' ) {
                                    obj[propName] = _deserializeObject(self, prop);
                                }
                                else {
                                    _deserializeObjField(self, obj, prop, propName);
                                }
                            }
                            else {
                                obj[propName] = null;
                            }
                        }
                    }
                }
                else {
                    // always load host objects even if property not serialized
                    if (self.result.hostProp) {
                        Fire.error('not support multi host object in a file');
                        // 这里假定每个asset都有uuid，每个json只能包含一个asset，只能包含一个hostProp
                    }
                    self.result.hostProp = propName;
                }
            }
            if (props[props.length - 1] === '_$erialized') {
                // save original serialized data
                obj._$erialized = serialized;
                // parse the serialized data as primitive javascript object, so its __id__ will be dereferenced
                _deserializePrimitiveObject(self, obj._$erialized, serialized);
            }
        }
        else {
            _deserializePrimitiveObject(self, obj, serialized);
        }
        return obj;
    };

    return _Deserializer;
})();

/**
 * Deserialize json to Fire.Asset
 * @param {(string|object)} data - the serialized Fire.Asset json string or json object.
 *                                 Note: If data is an object, it will be modified.
 * @param {Fire._DeserializeInfo} [result] - additional loading result
 * @param {object} [options=null]
 * @returns {object} the main data(asset)
 */
Fire.deserialize = function (data, result, options) {
    var isEditor = (options && 'isEditor' in options) ? options.isEditor : Fire.isEditor;
    var classFinder = (options && options.classFinder) || Fire.getClassByName;
    var createAssetRefs = (options && options.createAssetRefs) || Fire.isEditorCore;

    // @ifndef PLAYER
    if (Fire.isNode && Buffer.isBuffer(data)) {
        data = data.toString();
    }
    // @endif

    if (typeof data === 'string') {
        data = JSON.parse(data);
    }

    if (createAssetRefs && !result) {
        result = new Fire._DeserializeInfo();
    }

    Fire._isCloning = true;
    var deserializer = new _Deserializer(data, result, isEditor, classFinder);
    Fire._isCloning = false;

    if (createAssetRefs) {
        result.createAssetRefs();
    }

    return deserializer.deserializedData;
};

/**
 * 包含反序列化时的一些信息
 * @class Fire._DeserializeInfo
 */
Fire._DeserializeInfo = function () {

    //this.urlList = [];
    //this.callbackList = [];

    // uuids(assets) need to load

    /**
     * @property {string[]} uuidList - list of the depends assets' uuid
     */
    this.uuidList = [];
    /**
     * @property {object[]} uuidObjList - the obj list whose field needs to load asset by uuid
     */
    this.uuidObjList = [];
    /**
     * @property {string[]} uuidPropList - the corresponding field name which referenced to the asset
     */
    this.uuidPropList = [];

    // host objects need to load
    // (不用存hostList因为它的uuid可以从asset上获得)

    /**
     * @property {string} hostProp - the corresponding field name which referenced to the host object
     */
    this.hostProp = '';
    ///**
    // * @property {Fire.Asset[]} hostObjList - the obj list whose corresponding host object needs to load
    // */
    //this.hostObjList = [];
    ///**
    // * @property {string[]} hostPropList - the corresponding field name which referenced to the host object
    // */
    //this.hostPropList = [];
};

Fire._DeserializeInfo.prototype.reset = function () {
    this.uuidList.length = 0;
    this.uuidObjList.length = 0;
    this.uuidPropList.length = 0;
    this.hostProp = '';
    //this.hostObjList.length = 0;
    //this.hostPropList.length = 0;
};

Fire._DeserializeInfo.prototype.getUuidOf = function (obj, propName) {
    for (var i = 0; i < this.uuidObjList.length; i++) {
        if (this.uuidObjList[i] === obj && this.uuidPropList[i] === propName) {
            return this.uuidList[i];
        }
    }
    return "";
};

Fire._DeserializeInfo.prototype.createAssetRefs = function () {
    for (var i = 0; i < this.uuidObjList.length; i++) {
        var obj = this.uuidObjList[i];
        var prop = this.uuidPropList[i];
        var uuid = this.uuidList[i];
        obj[prop] = Fire.serialize.asAsset(uuid);
    }
};
<commit_msg>small refactoring<commit_after>
var _Deserializer = (function () {
    /**
     * @param {boolean} isEditor - if false, property with Fire.EditorOnly will be discarded
     */
    function _Deserializer(jsonObj, result, isEditor, classFinder) {
        this._editor = isEditor;
        this._classFinder = classFinder;

        this._idList = [];
        this._idObjList = [];
        this._idPropList = [];
        this.result = result || new Fire._DeserializeInfo();

        if (Array.isArray(jsonObj)) {
            var jsonList = jsonObj;
            var refCount = jsonList.length;
            this.deserializedList = new Array(refCount);
            // deserialize
            for (var i = 0; i < refCount; i++) {
                if (jsonList[i]) {
                    this.deserializedList[i] = _deserializeObject(this, jsonList[i]);
                }
            }
            this.deserializedData = refCount > 0 ? this.deserializedList[0] : [];

            //// callback
            //for (var j = 0; j < refCount; j++) {
            //    if (referencedList[j].onAfterDeserialize) {
            //        referencedList[j].onAfterDeserialize();
            //    }
            //}
        }
        else {
            this.deserializedList = new Array(1);
            this.deserializedData = jsonObj ? _deserializeObject(this, jsonObj) : null;
            this.deserializedList[0] = this.deserializedData;

            //// callback
            //if (deserializedData.onAfterDeserialize) {
            //    deserializedData.onAfterDeserialize();
            //}
        }

        // dereference
        _dereference(this);
    }

    var _dereference = function (self) {
        // 这里不采用遍历反序列化结果的方式，因为反序列化的结果如果引用到复杂的外部库，很容易堆栈溢出。
        var deserializedList = self.deserializedList;
        for (var i = 0, len = self._idList.length; i < len; i++) {
            var propName = self._idPropList[i];
            var id = self._idList[i];
            self._idObjList[i][propName] = deserializedList[id];
        }
    };

    function _deserializeObjField (self, obj, jsonObj, propName) {
        var id = jsonObj.__id__;
        if (typeof id === 'undefined') {
            var uuid = jsonObj.__uuid__;
            if (uuid) {
                self.result.uuidList.push(uuid);
                self.result.uuidObjList.push(obj);
                self.result.uuidPropList.push(propName);
            }
            else {
                obj[propName] = _deserializeObject(self, jsonObj);
            }
        }
        else {
            var dObj = self.deserializedList[id];
            if (dObj) {
                obj[propName] = dObj;
            }
            else {
                self._idList.push(id);
                self._idObjList.push(obj);
                self._idPropList.push(propName);
            }
        }
    }

    function _deserializePrimitiveObject (self, instance, serialized) {
        for (var propName in instance) {    // 遍历 instance，如果具有类型，才不会把 __type__ 也读进来
            var prop = serialized[propName];
            if (typeof prop !== 'undefined' && serialized.hasOwnProperty(propName)) {
                if (typeof prop !== 'object') {
                    instance[propName] = prop;
                }
                else {
                    if (prop) {
                        if ( !prop.__uuid__ && typeof prop.__id__ === 'undefined' ) {
                            instance[propName] = _deserializeObject(self, prop);
                        }
                        else {
                            _deserializeObjField(self, instance, prop, propName);
                        }
                    }
                    else {
                        instance[propName] = null;
                    }
                }
            }
        }
    }

    /**
     * @param {Object} serialized - The obj to deserialize, must be non-nil
     */
    var _deserializeObject = function (self, serialized) {
        var propName, prop;
        var obj = null;
        var klass = null;
        if (serialized.__type__) {
            klass = self._classFinder(serialized.__type__);
            if (!klass) {
                Fire.error('[Fire.deserialize] unknown type: ' + serialized.__type__);
                return null;
            }
            // instantiate a new object
            obj = new klass();
        }
        else if (!Array.isArray(serialized)) {
            // embedded primitive javascript object
            obj = serialized;
            //// jshint -W010
            //obj = new Object();
            //// jshint +W010
        }
        else {
            // array
            obj = serialized;
            for (var i = 0; i < serialized.length; i++) {
                prop = serialized[i];
                if (typeof prop === 'object' && prop) {
                    if (!prop.__uuid__ && typeof prop.__id__ === 'undefined') {
                        obj[i] = _deserializeObject(self, prop);
                    }
                    else {
                        _deserializeObjField(self, obj, prop, '' + i);
                    }
                }
            }
            return serialized;
        }

        // parse property
        if (klass && Fire._isFireClass(klass)) {
            var props = klass.__props__;
            if (!props) {
                return obj;
            }
            for (var p = 0; p < props.length; p++) {
                propName = props[p];
                var attrs = Fire.attr(klass, propName);
                // assume all prop in __props__ must have attr
                var hostType = attrs.hostType;
                if (!hostType) {
                    if (attrs.serializable === false) {
                        continue;   // skip nonSerialized
                    }
                    if (!self._editor && attrs.editorOnly) {
                        continue;   // skip editor only if not editor
                    }
                    prop = serialized[propName];
                    if (typeof prop !== 'undefined') {
                        if (typeof prop !== 'object') {
                            obj[propName] = prop;
                        }
                        else {
                            if (prop) {
                                if ( !prop.__uuid__ && typeof prop.__id__ === 'undefined' ) {
                                    obj[propName] = _deserializeObject(self, prop);
                                }
                                else {
                                    _deserializeObjField(self, obj, prop, propName);
                                }
                            }
                            else {
                                obj[propName] = null;
                            }
                        }
                    }
                }
                else {
                    // always load host objects even if property not serialized
                    if (self.result.hostProp) {
                        Fire.error('not support multi host object in a file');
                        // 这里假定每个asset都有uuid，每个json只能包含一个asset，只能包含一个hostProp
                    }
                    self.result.hostProp = propName;
                }
            }
            if (props[props.length - 1] === '_$erialized') {
                // save original serialized data
                obj._$erialized = serialized;
                // parse the serialized data as primitive javascript object, so its __id__ will be dereferenced
                _deserializePrimitiveObject(self, obj._$erialized, serialized);
            }
        }
        else {
            _deserializePrimitiveObject(self, obj, serialized);
        }
        return obj;
    };

    return _Deserializer;
})();

/**
 * Deserialize json to Fire.Asset
 * @param {(string|object)} data - the serialized Fire.Asset json string or json object.
 *                                 Note: If data is an object, it will be modified.
 * @param {Fire._DeserializeInfo} [result] - additional loading result
 * @param {object} [options=null]
 * @returns {object} the main data(asset)
 */
Fire.deserialize = function (data, result, options) {
    var isEditor = (options && 'isEditor' in options) ? options.isEditor : Fire.isEditor;
    var classFinder = (options && options.classFinder) || Fire.getClassByName;
    var createAssetRefs = (options && options.createAssetRefs) || Fire.isEditorCore;

    // @ifndef PLAYER
    if (Fire.isNode && Buffer.isBuffer(data)) {
        data = data.toString();
    }
    // @endif

    if (typeof data === 'string') {
        data = JSON.parse(data);
    }

    if (createAssetRefs && !result) {
        result = new Fire._DeserializeInfo();
    }

    Fire._isCloning = true;
    var deserializer = new _Deserializer(data, result, isEditor, classFinder);
    Fire._isCloning = false;

    if (createAssetRefs) {
        result.assignAssetsBy(Fire.serialize.asAsset);
    }

    return deserializer.deserializedData;
};

/**
 * 包含反序列化时的一些信息
 * @class Fire._DeserializeInfo
 */
Fire._DeserializeInfo = function () {

    //this.urlList = [];
    //this.callbackList = [];

    // uuids(assets) need to load

    /**
     * @property {string[]} uuidList - list of the depends assets' uuid
     */
    this.uuidList = [];
    /**
     * @property {object[]} uuidObjList - the obj list whose field needs to load asset by uuid
     */
    this.uuidObjList = [];
    /**
     * @property {string[]} uuidPropList - the corresponding field name which referenced to the asset
     */
    this.uuidPropList = [];

    // host objects need to load
    // (不用存hostList因为它的uuid可以从asset上获得)

    /**
     * @property {string} hostProp - the corresponding field name which referenced to the host object
     */
    this.hostProp = '';
    ///**
    // * @property {Fire.Asset[]} hostObjList - the obj list whose corresponding host object needs to load
    // */
    //this.hostObjList = [];
    ///**
    // * @property {string[]} hostPropList - the corresponding field name which referenced to the host object
    // */
    //this.hostPropList = [];
};

Fire._DeserializeInfo.prototype.reset = function () {
    this.uuidList.length = 0;
    this.uuidObjList.length = 0;
    this.uuidPropList.length = 0;
    this.hostProp = '';
    //this.hostObjList.length = 0;
    //this.hostPropList.length = 0;
};

Fire._DeserializeInfo.prototype.getUuidOf = function (obj, propName) {
    for (var i = 0; i < this.uuidObjList.length; i++) {
        if (this.uuidObjList[i] === obj && this.uuidPropList[i] === propName) {
            return this.uuidList[i];
        }
    }
    return "";
};

Fire._DeserializeInfo.prototype.assignAssetsBy = function (callback) {
    for (var i = 0, len = this.uuidList.length; i < len; i++) {
        var uuid = this.uuidList[i];
        var asset = callback(uuid);
        if (asset) {
            var obj = this.uuidObjList[i];
            var prop = this.uuidPropList[i];
            obj[prop] = asset;
        }
        else {
            Fire.error('Failed to assign asset: ' + uuid);
        }
    }
};
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.ui.form.on("Customer", {
	setup: function(frm) {
		frm.add_fetch('lead_name', 'company_name', 'customer_name');
		frm.add_fetch('default_sales_partner','commission_rate','default_commission_rate');

		frm.set_query('customer_group', {'is_group': 0});
		frm.set_query('default_price_list', { 'selling': 1});
		frm.set_query('account', 'accounts', function(doc, cdt, cdn) {
			var d  = locals[cdt][cdn];
			var filters = {
				'account_type': 'Receivable',
				'company': d.company,
				"is_group": 0
			};

			if(doc.party_account_currency) {
				$.extend(filters, {"account_currency": doc.party_account_currency});
			}

			return {
				filters: filters
			}
		});

		frm.set_query('customer_primary_contact', function(doc) {
			return {
				query: "erpnext.selling.doctype.customer.customer.get_customer_primary_contact",
				filters: {
					'customer': doc.name
				}
			}
		})
		frm.set_query('customer_primary_address', function(doc) {
			return {
				query: "erpnext.selling.doctype.customer.customer.get_customer_primary_address",
				filters: {
					'customer': doc.name
				}
			}
		})
	},
	customer_primary_address: function(frm){
		if(frm.doc.customer_primary_address){
			frappe.call({
				doc: frm.doc,
				args: {
					"address_title": frm.doc.customer_primary_address
				},
				method: 'frappe.contacts.doctype.address.address.get_address_display',
				callback: function(r) {
					frm.set_value("primary_address", r.message);
				}
			});
		}
		if(!frm.doc.customer_primary_address){
			frm.set_value("primary_address", "");
		}
	},
	customer_primary_contact: function(frm){
		if(!frm.doc.customer_primary_contact){
			frm.set_value("mobile_no", "");
			frm.set_value("email_id", "");
		}
	},

	refresh: function(frm) {
		if(frappe.defaults.get_default("cust_master_name")!="Naming Series") {
			frm.toggle_display("naming_series", false);
		} else {
			erpnext.toggle_naming_series();
		}

		frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Customer'}

		frm.toggle_display(['address_html','contact_html','primary_address_and_contact_detail'], !frm.doc.__islocal);

		if(!frm.doc.__islocal) {
			frappe.contacts.render_address_and_contact(frm);

			// custom buttons
			frm.add_custom_button(__('Accounting Ledger'), function() {
				frappe.set_route('query-report', 'General Ledger',
					{party_type:'Customer', party:frm.doc.name});
			});

			frm.add_custom_button(__('Accounts Receivable'), function() {
				frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name});
			});

			// indicator
			erpnext.utils.set_party_dashboard_indicators(frm);

		} else {
			frappe.contacts.clear_address_and_contact(frm);
		}

		var grid = cur_frm.get_field("sales_team").grid;
		grid.set_column_disp("allocated_amount", false);
		grid.set_column_disp("incentives", false);
	},
	validate: function(frm) {
		if(frm.doc.lead_name) frappe.model.clear_doc("Lead", frm.doc.lead_name);
	},
});<commit_msg>[Fix] Bug fix in customer_primary_address frappe call (#12880)<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.ui.form.on("Customer", {
	setup: function(frm) {
		frm.add_fetch('lead_name', 'company_name', 'customer_name');
		frm.add_fetch('default_sales_partner','commission_rate','default_commission_rate');

		frm.set_query('customer_group', {'is_group': 0});
		frm.set_query('default_price_list', { 'selling': 1});
		frm.set_query('account', 'accounts', function(doc, cdt, cdn) {
			var d  = locals[cdt][cdn];
			var filters = {
				'account_type': 'Receivable',
				'company': d.company,
				"is_group": 0
			};

			if(doc.party_account_currency) {
				$.extend(filters, {"account_currency": doc.party_account_currency});
			}

			return {
				filters: filters
			}
		});

		frm.set_query('customer_primary_contact', function(doc) {
			return {
				query: "erpnext.selling.doctype.customer.customer.get_customer_primary_contact",
				filters: {
					'customer': doc.name
				}
			}
		})
		frm.set_query('customer_primary_address', function(doc) {
			return {
				query: "erpnext.selling.doctype.customer.customer.get_customer_primary_address",
				filters: {
					'customer': doc.name
				}
			}
		})
	},
	customer_primary_address: function(frm){
		if(frm.doc.customer_primary_address){
			frappe.call({
				method: 'frappe.contacts.doctype.address.address.get_address_display',
				args: {
					"address_dict": frm.doc.customer_primary_address
				},
				callback: function(r) {
					frm.set_value("primary_address", r.message);
				}
			});
		}
		if(!frm.doc.customer_primary_address){
			frm.set_value("primary_address", "");
		}
	},
	customer_primary_contact: function(frm){
		if(!frm.doc.customer_primary_contact){
			frm.set_value("mobile_no", "");
			frm.set_value("email_id", "");
		}
	},

	refresh: function(frm) {
		if(frappe.defaults.get_default("cust_master_name")!="Naming Series") {
			frm.toggle_display("naming_series", false);
		} else {
			erpnext.toggle_naming_series();
		}

		frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Customer'}

		frm.toggle_display(['address_html','contact_html','primary_address_and_contact_detail'], !frm.doc.__islocal);

		if(!frm.doc.__islocal) {
			frappe.contacts.render_address_and_contact(frm);

			// custom buttons
			frm.add_custom_button(__('Accounting Ledger'), function() {
				frappe.set_route('query-report', 'General Ledger',
					{party_type:'Customer', party:frm.doc.name});
			});

			frm.add_custom_button(__('Accounts Receivable'), function() {
				frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name});
			});

			// indicator
			erpnext.utils.set_party_dashboard_indicators(frm);

		} else {
			frappe.contacts.clear_address_and_contact(frm);
		}

		var grid = cur_frm.get_field("sales_team").grid;
		grid.set_column_disp("allocated_amount", false);
		grid.set_column_disp("incentives", false);
	},
	validate: function(frm) {
		if(frm.doc.lead_name) frappe.model.clear_doc("Lead", frm.doc.lead_name);
	},
});<|endoftext|>


<commit_before>// SortedLayout Container
// Original Author: Daniel Plemmons
// Created: Nov. 3, 2014
//
// This is a container for InteractablePlanes that:
// - Allows the planes to be interactively layed out on screen
//   (via sorting) by given properties
// - Allows users to determine the behavior of the on-screen
//   sorting based on the position of their hands
// - Allows the user to manually layout the items in the
//   container and persists that layout in application state
//   (for the duration of the application runtime)
//
// For the moment, the container will make all calculations for
// the plane locations in world space. Eventually this class
// should be modified to give each container it's own local
// coordinate space.
//
// The container currently handles it's own list of child planes.
// This means that multiple containers could reasonably contain
// the same plane. This class should eventually be refactored to
// have the plane's parent determine its container. ( this goes along
// with the proposed coordinate space refactor. )

(function () {
  //The list of valid states for the manner of sorting.
  var validSortStates = [
    "USER_SORTED",
    "DYNAMIC_SORTED"
  ];
  // SortedLayoutContainer Constructor
  // Optional argument "planeList" is a list of InteractivePlanes to be added to the container on creation
  // Optional argument "sortState" is a string given one of the validSortStates listed above.
  window.SortedLayoutContainer = function(planeList, sortState){
    this.planeList = planeList || [];

    if (sortState !== undefined && validSortStates.indexOf(sortState) != -1) {
      this.changeSortState(sortState);
    }
    else {
      this.changeSortState("USER_SORTED");
    }
  };

  // Pubic Methods
  window.SortedLayoutContainer.prototype = {
    // Takes two hand positions
    // if the container's current state allows programatic layout (as opposed to manual user layout )
    // will sort the InteractablePlane(s) in the container accordingly (and return true).
    // Update will return false if the current container state does not support
    // programatic layout
    update: function(hand1, hand2) {
      var hand1Position = new THREE.Vector3().copy(hand1);
      var hand2Position = new THREE.Vector3().copy(hand2);
      var fromTwoToOne = new THREE.Vector3().copy(hand2Position).sub(hand1Position);

      var leftmost = hand1Position.x < hand2Position.x ? hand1Position : hand2Position;
      var rightmost = hand1Position.x < hand2Position.x ? hand2Position : hand1Position;
      var topmost = hand1Position.x < hand2Position.x ? hand1Position : hand2Position;
      var bottommost = hand1Position.x < hand2Position.x ? hand1Position : hand2Position;

      var start = Math.abs(fromTwoToOne.x) > Math.abs(fromTwoToOne.y) ? leftmost : topmost;
      var end = Math.abs(fromTwoToOne.x) > Math.abs(fromTwoToOne.y) ? rightmost : bottommost;

      if ( this.sortState == "DYNAMIC_SORTED" ) {
        var diff = new THREE.Vector3().copy(rightmost).sub(leftmost);
        var weightX = diff.x / (diff.x + diff.y);
        var weightY = diff.y / (diff.x + diff.y);
        var alphabeticalLayout = listLayout(this.planeList, leftmost, new THREE.Vector3(leftmost.x + diff.x, leftmost.y, leftmost.z)).alphabetical();
        var chronologicalLayout = listLayout(this.planeList, leftmost, new THREE.Vector3(leftmost.x, leftmost.y + diff.y, leftmost.z)).alphabetical();
        var blendedLayout = blendLayouts([alphabeticalLayout, chronologicalLayout], [weightX, weightY]);
        applyLayoutList(blendedLayout);
        return true;
      }
      else {
        return false;
      }
    },

    changeSortState: function(newSortState) {
      if (validSortStates.indexOf(newSortState) == -1 || newSortState == this.sortState) {
        return false;
      }

      if ( newSortState == "DYNAMIC_SORTED" ) {
        for(var i=0; i<this.planeList.length; i++) {
          this.planeList[i].interactable = false;
        }
      }
      else if ( newSortState == "USER_SORTED" ) {
        for(var i=0; i<this.planeList.length; i++) {
          this.planeList[i].interactable = true;
        }
      }

      this.sortState = newSortState;
    },

    // Adds the given plane to list of planes managed by the container.
    // Returns true if the plane is successfully added.
    // Returns false if the plane is a duplicate and cannot be added.
    addPlane: function(newPlane) {
      if ( this.planeList.indexOf(newPlane) == -1 ) {
        if ( this.sortState == "DYNAMIC_SORTED" ) {
          newPlane.interactable = false;
        }
        this.planeList.push(newPlane);
        return true;
      }
      else {
        return false;
      }
    },

    // Removes the given plane from the list of planes.
    // Returns true if the plane was successfully removed.
    // Returns false if the plane could not be found and was not removed.
    removePlane: function(toRemove) {
      var planeIndex;
      if ( (planeIndex = this.planeList.indexOf(toRemove)) != -1 ) {
        toRemove.interactable = true;
        this.planeList.splice(planeIndex, 1);
        return true;
      }
      else {
        return false;
      }
    }
  };

  // Generates a LayoutNode object which is just a
  // simple structure to hold a plane and the position
  // generated for it.
  function LayoutNode(plane, position) {
    var returnNode = {
      "plane": plane,
      "position": position
    };
    return returnNode;
  }

  // If called with a sort comparitor, returns an array of layoutNodes specifying the InteractivePlane and the
  // location in space according to the supplied sort comparitor function.
  //
  // if called with just start and end position, returns an object that containts the relevant
  // calls to generate the layout with different sorting properties.
  function listLayout(planeList, start, end, sortComparitor) {
    var startPosition = new THREE.Vector3().copy(start);
    var endPosition = new THREE.Vector3().copy(end);

    // If only start and end position are given, utilize partial evaluation
    // to allow a call formated like: listLayout(startPosition, endPosition).alphabetical();
    if (arguments.length == 3) {
      return {
        alphabetical: (function() {
          return listLayout(planeList, startPosition, endPosition, function(a,b) {
            if ( a.mesh.name <= b.mesh.name ) { return -1; }
            else { return 1; }
          });
        }),
        chronological: (function() {
          return listLayout(planeList, startPosition, endPosition, function(a,b) {
            if ( a.uid <= b.uid ) { return -1; }
            else { return 1; }
          });
        })
      };
    }
    else if (arguments.length == 4) {
      var layoutList = [];

      // Sort the planelist alphabetically by "plane.mesh.name"
      planeList.sort(sortComparitor);

      // Generate the layout list full of layout nodes
      for (var i=0; i<planeList.length; i++) {
        var plane = planeList[i];
        var listPercentage = (i*1.0) / (planeList.length*1.0); // force double division
        listPercentage = Math.min(1.0, Math.max(0.0, listPercentage));
        var position = new THREE.Vector3().copy(startPosition).lerp(endPosition, listPercentage);

        layoutList.push(LayoutNode(plane, position));
      }

      return layoutList;
    }
    else {
      return false;
    }
  }

  // - Retruns a weighted mean of the given layout node lists as an array of layout nodes
  // - Assumes that each index of each list in layout lists referes to the
  //   same node.
  // - The length of the weightList and the layoutList must be equal.
  function blendLayouts(layoutLists, weightList) {
    var ittr = 0;
    var weightSumList = [];
    var vectorSumList = [];
    var blendedLayoutList = [];

    // Confirm arguments are valid(ish)
    if( layoutLists === undefined || weightList === undefined) { return false; }
    else if ( !(Array.isArray(layoutLists)) || !(Array.isArray(layoutLists))) { return false; }
    else if ( layoutLists.length != weightList.length ) { return false; }
    else if ( layoutLists.length === 0 ) { return false; }

    // For each node, calculate the weighted sum of vectors
    // along with the sum of weights.
    for( var i=0; i < layoutLists.length; i++ ) {
      var layoutList = layoutLists[i];
      var weight = weightList[i];
      for ( var j=0; j<layoutList.length; j++ ) {
        var layoutNode = layoutList[j];
        if (vectorSumList[j] === undefined) { vectorSumList[j] = new THREE.Vector3().copy(layoutNode.position).multiplyScalar(weight); }
        else { vectorSumList[j].add(new THREE.Vector3().copy(layoutNode.position).multiplyScalar(weight)); }

        if (weightSumList[j] === undefined) { weightSumList[j] = weight; }
        else { weightSumList[j] += weight; }
      }
    }

    //Calculate the weighted mean for each node
    for ( var i=0; i < vectorSumList.length; i++) {
      vecSum = vectorSumList[i];
      var plane = layoutLists[0][i].plane;
      var weightSum = weightSumList[i];
      blendedLayoutList[i] = LayoutNode(plane, new THREE.Vector3().copy(vecSum).divideScalar(weightSum));
    }

    return blendedLayoutList;
  }

  // Itterate through a layout list and move the given elements to the
  // given positions.
  function applyLayoutList(layoutList) {
    for(var i=0; i<layoutList.length; i++) {
      var node = layoutList[i];
      var plane = node.plane;
      plane.mesh.position.copy(node.position);
    }
  }
}).call(this);<commit_msg>manage hand ordering for layouts.<commit_after>// SortedLayout Container
// Original Author: Daniel Plemmons
// Created: Nov. 3, 2014
//
// This is a container for InteractablePlanes that:
// - Allows the planes to be interactively layed out on screen
//   (via sorting) by given properties
// - Allows users to determine the behavior of the on-screen
//   sorting based on the position of their hands
// - Allows the user to manually layout the items in the
//   container and persists that layout in application state
//   (for the duration of the application runtime)
//
// For the moment, the container will make all calculations for
// the plane locations in world space. Eventually this class
// should be modified to give each container it's own local
// coordinate space.
//
// The container currently handles it's own list of child planes.
// This means that multiple containers could reasonably contain
// the same plane. This class should eventually be refactored to
// have the plane's parent determine its container. ( this goes along
// with the proposed coordinate space refactor. )

(function () {
  //The list of valid states for the manner of sorting.
  var validSortStates = [
    "USER_SORTED",
    "DYNAMIC_SORTED"
  ];
  // SortedLayoutContainer Constructor
  // Optional argument "planeList" is a list of InteractivePlanes to be added to the container on creation
  // Optional argument "sortState" is a string given one of the validSortStates listed above.
  window.SortedLayoutContainer = function(planeList, sortState){
    this.planeList = planeList || [];

    if (sortState !== undefined && validSortStates.indexOf(sortState) != -1) {
      this.changeSortState(sortState);
    }
    else {
      this.changeSortState("USER_SORTED");
    }
  };

  // Pubic Methods
  window.SortedLayoutContainer.prototype = {
    // Takes two hand positions
    // if the container's current state allows programatic layout (as opposed to manual user layout )
    // will sort the InteractablePlane(s) in the container accordingly (and return true).
    // Update will return false if the current container state does not support
    // programatic layout
    update: function(hand1, hand2) {
      var hand1Position = new THREE.Vector3().copy(hand1);
      var hand2Position = new THREE.Vector3().copy(hand2);
      var fromTwoToOne = new THREE.Vector3().copy(hand2Position).sub(hand1Position);

      var leftmost = hand1Position.x < hand2Position.x ? hand1Position : hand2Position;
      var rightmost = hand1Position.x < hand2Position.x ? hand2Position : hand1Position;
      var topmost = hand1Position.y < hand2Position.y ? hand1Position : hand2Position;
      var bottommost = hand1Position.y < hand2Position.y ? hand2Position : hand1Position;

      if ( this.sortState == "DYNAMIC_SORTED" ) {
        // Figure out the weighting of each layout
        var diff = new THREE.Vector3().copy(rightmost).sub(leftmost);
        var weightX = diff.x / (diff.x + diff.y);
        var weightY = diff.y / (diff.x + diff.y);

        var alphabeticalLayout = listLayout(this.planeList, leftmost, new THREE.Vector3(rightmost.x, leftmost.y, leftmost.z)).alphabetical();
        var chronologicalLayout = listLayout(this.planeList, bottommost, new THREE.Vector3(bottommost.x, topmost.y, bottommost.z)).alphabetical();
        var blendedLayout = blendLayouts([alphabeticalLayout, chronologicalLayout], [weightX, weightY]);
        applyLayoutList(blendedLayout);
        return true;
      }
      else {
        return false;
      }
    },

    changeSortState: function(newSortState) {
      if (validSortStates.indexOf(newSortState) == -1 || newSortState == this.sortState) {
        return false;
      }

      if ( newSortState == "DYNAMIC_SORTED" ) {
        for(var i=0; i<this.planeList.length; i++) {
          this.planeList[i].interactable = false;
        }
      }
      else if ( newSortState == "USER_SORTED" ) {
        for(var i=0; i<this.planeList.length; i++) {
          this.planeList[i].interactable = true;
        }
      }

      this.sortState = newSortState;
    },

    // Adds the given plane to list of planes managed by the container.
    // Returns true if the plane is successfully added.
    // Returns false if the plane is a duplicate and cannot be added.
    addPlane: function(newPlane) {
      if ( this.planeList.indexOf(newPlane) == -1 ) {
        if ( this.sortState == "DYNAMIC_SORTED" ) {
          newPlane.interactable = false;
        }
        this.planeList.push(newPlane);
        return true;
      }
      else {
        return false;
      }
    },

    // Removes the given plane from the list of planes.
    // Returns true if the plane was successfully removed.
    // Returns false if the plane could not be found and was not removed.
    removePlane: function(toRemove) {
      var planeIndex;
      if ( (planeIndex = this.planeList.indexOf(toRemove)) != -1 ) {
        toRemove.interactable = true;
        this.planeList.splice(planeIndex, 1);
        return true;
      }
      else {
        return false;
      }
    }
  };

  // Generates a LayoutNode object which is just a
  // simple structure to hold a plane and the position
  // generated for it.
  function LayoutNode(plane, position) {
    var returnNode = {
      "plane": plane,
      "position": position
    };
    return returnNode;
  }

  // If called with a sort comparitor, returns an array of layoutNodes specifying the InteractivePlane and the
  // location in space according to the supplied sort comparitor function.
  //
  // if called with just start and end position, returns an object that containts the relevant
  // calls to generate the layout with different sorting properties.
  function listLayout(planeList, start, end, sortComparitor) {
    var startPosition = new THREE.Vector3().copy(start);
    var endPosition = new THREE.Vector3().copy(end);

    // If only start and end position are given, utilize partial evaluation
    // to allow a call formated like: listLayout(startPosition, endPosition).alphabetical();
    if (arguments.length == 3) {
      return {
        alphabetical: (function() {
          return listLayout(planeList, startPosition, endPosition, function(a,b) {
            if ( a.mesh.name <= b.mesh.name ) { return -1; }
            else { return 1; }
          });
        }),
        chronological: (function() {
          return listLayout(planeList, startPosition, endPosition, function(a,b) {
            if ( a.uid <= b.uid ) { return -1; }
            else { return 1; }
          });
        })
      };
    }
    else if (arguments.length == 4) {
      var layoutList = [];

      // Sort the planelist alphabetically by "plane.mesh.name"
      planeList.sort(sortComparitor);

      // Generate the layout list full of layout nodes
      for (var i=0; i<planeList.length; i++) {
        var plane = planeList[i];
        var listPercentage = (i*1.0) / (planeList.length*1.0); // force double division
        listPercentage = Math.min(1.0, Math.max(0.0, listPercentage));
        var position = new THREE.Vector3().copy(startPosition).lerp(endPosition, listPercentage);

        layoutList.push(LayoutNode(plane, position));
      }

      return layoutList;
    }
    else {
      return false;
    }
  }

  // - Retruns a weighted mean of the given layout node lists as an array of layout nodes
  // - Assumes that each index of each list in layout lists referes to the
  //   same node.
  // - The length of the weightList and the layoutList must be equal.
  function blendLayouts(layoutLists, weightList) {
    var ittr = 0;
    var weightSumList = [];
    var vectorSumList = [];
    var blendedLayoutList = [];

    // Confirm arguments are valid(ish)
    if( layoutLists === undefined || weightList === undefined) { return false; }
    else if ( !(Array.isArray(layoutLists)) || !(Array.isArray(layoutLists))) { return false; }
    else if ( layoutLists.length != weightList.length ) { return false; }
    else if ( layoutLists.length === 0 ) { return false; }

    // For each node, calculate the weighted sum of vectors
    // along with the sum of weights.
    for( var i=0; i < layoutLists.length; i++ ) {
      var layoutList = layoutLists[i];
      var weight = weightList[i];
      for ( var j=0; j<layoutList.length; j++ ) {
        var layoutNode = layoutList[j];
        if (vectorSumList[j] === undefined) { vectorSumList[j] = new THREE.Vector3().copy(layoutNode.position).multiplyScalar(weight); }
        else { vectorSumList[j].add(new THREE.Vector3().copy(layoutNode.position).multiplyScalar(weight)); }

        if (weightSumList[j] === undefined) { weightSumList[j] = weight; }
        else { weightSumList[j] += weight; }
      }
    }

    //Calculate the weighted mean for each node
    for ( var i=0; i < vectorSumList.length; i++) {
      vecSum = vectorSumList[i];
      var plane = layoutLists[0][i].plane;
      var weightSum = weightSumList[i];
      blendedLayoutList[i] = LayoutNode(plane, new THREE.Vector3().copy(vecSum).divideScalar(weightSum));
    }

    return blendedLayoutList;
  }

  // Itterate through a layout list and move the given elements to the
  // given positions.
  function applyLayoutList(layoutList) {
    for(var i=0; i<layoutList.length; i++) {
      var node = layoutList[i];
      var plane = node.plane;
      plane.mesh.position.copy(node.position);
    }
  }
}).call(this);<|endoftext|>